@docusaurus/plugin-content-blog 3.3.2 → 3.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/atom.css +75 -0
- package/assets/atom.xsl +92 -0
- package/assets/rss.css +75 -0
- package/assets/rss.xsl +86 -0
- package/lib/authors.d.ts +9 -11
- package/lib/authors.js +42 -64
- package/lib/authorsMap.d.ts +23 -0
- package/lib/authorsMap.js +116 -0
- package/lib/authorsProblems.d.ts +21 -0
- package/lib/authorsProblems.js +51 -0
- package/lib/authorsSocials.d.ts +10 -0
- package/lib/authorsSocials.js +48 -0
- package/lib/blogUtils.d.ts +7 -12
- package/lib/blogUtils.js +44 -34
- package/lib/client/contexts.d.ts +33 -0
- package/lib/client/contexts.js +54 -0
- package/lib/client/index.d.ts +3 -3
- package/lib/client/index.js +3 -9
- package/lib/client/sidebarUtils.d.ts +21 -0
- package/lib/client/sidebarUtils.js +49 -0
- package/lib/client/sidebarUtils.test.d.ts +7 -0
- package/lib/client/sidebarUtils.test.js +43 -0
- package/lib/client/structuredDataUtils.d.ts +10 -0
- package/lib/client/structuredDataUtils.js +122 -0
- package/lib/feed.d.ts +8 -3
- package/lib/feed.js +111 -20
- package/lib/frontMatter.d.ts +0 -1
- package/lib/frontMatter.js +3 -2
- package/lib/index.d.ts +0 -1
- package/lib/index.js +132 -105
- package/lib/markdownLoader.js +3 -7
- package/lib/options.d.ts +4 -1
- package/lib/options.js +107 -26
- package/lib/props.d.ts +9 -2
- package/lib/props.js +23 -3
- package/lib/remark/footnoteIDFixer.js +1 -1
- package/lib/routes.d.ts +0 -1
- package/lib/routes.js +82 -14
- package/lib/translations.d.ts +0 -1
- package/lib/translations.js +2 -3
- package/lib/types.d.ts +1 -8
- package/package.json +13 -10
- package/src/authors.ts +56 -93
- package/src/authorsMap.ts +171 -0
- package/src/authorsProblems.ts +72 -0
- package/src/authorsSocials.ts +64 -0
- package/src/blogUtils.ts +51 -46
- package/src/client/contexts.tsx +95 -0
- package/src/client/index.tsx +24 -0
- package/src/client/sidebarUtils.test.ts +52 -0
- package/src/client/sidebarUtils.tsx +85 -0
- package/src/client/structuredDataUtils.ts +178 -0
- package/src/feed.ts +197 -18
- package/src/frontMatter.ts +2 -0
- package/src/index.ts +182 -137
- package/src/markdownLoader.ts +3 -7
- package/src/options.ts +132 -32
- package/src/plugin-content-blog.d.ts +252 -113
- package/src/props.ts +41 -1
- package/src/routes.ts +102 -12
- package/src/types.ts +1 -6
- package/src/client/index.ts +0 -20
package/src/index.ts
CHANGED
|
@@ -18,22 +18,26 @@ import {
|
|
|
18
18
|
getContentPathList,
|
|
19
19
|
getDataFilePath,
|
|
20
20
|
DEFAULT_PLUGIN_ID,
|
|
21
|
+
resolveMarkdownLinkPathname,
|
|
22
|
+
type SourceToPermalink,
|
|
21
23
|
} from '@docusaurus/utils';
|
|
24
|
+
import {getTagsFilePathsToWatch} from '@docusaurus/utils-validation';
|
|
22
25
|
import {
|
|
23
|
-
getSourceToPermalink,
|
|
24
26
|
getBlogTags,
|
|
25
27
|
paginateBlogPosts,
|
|
26
28
|
shouldBeListed,
|
|
27
29
|
applyProcessBlogPosts,
|
|
28
30
|
generateBlogPosts,
|
|
31
|
+
reportUntruncatedBlogPosts,
|
|
29
32
|
} from './blogUtils';
|
|
30
33
|
import footnoteIDFixer from './remark/footnoteIDFixer';
|
|
31
34
|
import {translateContent, getTranslationFiles} from './translations';
|
|
32
|
-
import {createBlogFeedFiles} from './feed';
|
|
35
|
+
import {createBlogFeedFiles, createFeedHtmlHeadTags} from './feed';
|
|
33
36
|
|
|
34
37
|
import {createAllRoutes} from './routes';
|
|
38
|
+
import {checkAuthorsMapPermalinkCollisions, getAuthorsMap} from './authorsMap';
|
|
35
39
|
import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types';
|
|
36
|
-
import type {LoadContext, Plugin
|
|
40
|
+
import type {LoadContext, Plugin} from '@docusaurus/types';
|
|
37
41
|
import type {
|
|
38
42
|
PluginOptions,
|
|
39
43
|
BlogPostFrontMatter,
|
|
@@ -43,6 +47,37 @@ import type {
|
|
|
43
47
|
BlogContent,
|
|
44
48
|
BlogPaginated,
|
|
45
49
|
} from '@docusaurus/plugin-content-blog';
|
|
50
|
+
import type {Options as MDXLoaderOptions} from '@docusaurus/mdx-loader/lib/loader';
|
|
51
|
+
import type {RuleSetUseItem} from 'webpack';
|
|
52
|
+
|
|
53
|
+
const PluginName = 'docusaurus-plugin-content-blog';
|
|
54
|
+
|
|
55
|
+
// TODO this is bad, we should have a better way to do this (new lifecycle?)
|
|
56
|
+
// The source to permalink is currently a mutable map passed to the mdx loader
|
|
57
|
+
// for link resolution
|
|
58
|
+
// see https://github.com/facebook/docusaurus/pull/10185
|
|
59
|
+
function createSourceToPermalinkHelper() {
|
|
60
|
+
const sourceToPermalink: SourceToPermalink = new Map();
|
|
61
|
+
|
|
62
|
+
function computeSourceToPermalink(content: BlogContent): SourceToPermalink {
|
|
63
|
+
return new Map(
|
|
64
|
+
content.blogPosts.map(({metadata: {source, permalink}}) => [
|
|
65
|
+
source,
|
|
66
|
+
permalink,
|
|
67
|
+
]),
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Mutable map update :/
|
|
72
|
+
function update(content: BlogContent): void {
|
|
73
|
+
sourceToPermalink.clear();
|
|
74
|
+
computeSourceToPermalink(content).forEach((value, key) => {
|
|
75
|
+
sourceToPermalink.set(key, value);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {get: () => sourceToPermalink, update};
|
|
80
|
+
}
|
|
46
81
|
|
|
47
82
|
export default async function pluginContentBlog(
|
|
48
83
|
context: LoadContext,
|
|
@@ -55,22 +90,29 @@ export default async function pluginContentBlog(
|
|
|
55
90
|
localizationDir,
|
|
56
91
|
i18n: {currentLocale},
|
|
57
92
|
} = context;
|
|
93
|
+
|
|
94
|
+
const router = siteConfig.future.experimental_router;
|
|
95
|
+
const isBlogFeedDisabledBecauseOfHashRouter =
|
|
96
|
+
router === 'hash' && !!options.feedOptions.type;
|
|
97
|
+
if (isBlogFeedDisabledBecauseOfHashRouter) {
|
|
98
|
+
logger.warn(
|
|
99
|
+
`${PluginName} feed feature does not support the Hash Router. Feeds won't be generated.`,
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
58
103
|
const {onBrokenMarkdownLinks, baseUrl} = siteConfig;
|
|
59
104
|
|
|
60
105
|
const contentPaths: BlogContentPaths = {
|
|
61
106
|
contentPath: path.resolve(siteDir, options.path),
|
|
62
107
|
contentPathLocalized: getPluginI18nPath({
|
|
63
108
|
localizationDir,
|
|
64
|
-
pluginName:
|
|
109
|
+
pluginName: PluginName,
|
|
65
110
|
pluginId: options.id,
|
|
66
111
|
}),
|
|
67
112
|
};
|
|
68
113
|
const pluginId = options.id ?? DEFAULT_PLUGIN_ID;
|
|
69
114
|
|
|
70
|
-
const pluginDataDirRoot = path.join(
|
|
71
|
-
generatedFilesDir,
|
|
72
|
-
'docusaurus-plugin-content-blog',
|
|
73
|
-
);
|
|
115
|
+
const pluginDataDirRoot = path.join(generatedFilesDir, PluginName);
|
|
74
116
|
const dataDir = path.join(pluginDataDirRoot, pluginId);
|
|
75
117
|
// TODO Docusaurus v4 breaking change
|
|
76
118
|
// module aliasing should be automatic
|
|
@@ -83,8 +125,10 @@ export default async function pluginContentBlog(
|
|
|
83
125
|
contentPaths,
|
|
84
126
|
});
|
|
85
127
|
|
|
128
|
+
const sourceToPermalinkHelper = createSourceToPermalinkHelper();
|
|
129
|
+
|
|
86
130
|
return {
|
|
87
|
-
name:
|
|
131
|
+
name: PluginName,
|
|
88
132
|
|
|
89
133
|
getPathsToWatch() {
|
|
90
134
|
const {include} = options;
|
|
@@ -92,9 +136,16 @@ export default async function pluginContentBlog(
|
|
|
92
136
|
(contentPath) => include.map((pattern) => `${contentPath}/${pattern}`),
|
|
93
137
|
);
|
|
94
138
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
139
|
+
const tagsFilePaths = getTagsFilePathsToWatch({
|
|
140
|
+
contentPaths,
|
|
141
|
+
tags: options.tags,
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
return [
|
|
145
|
+
authorsMapFilePath,
|
|
146
|
+
...tagsFilePaths,
|
|
147
|
+
...contentMarkdownGlobs,
|
|
148
|
+
].filter(Boolean) as string[];
|
|
98
149
|
},
|
|
99
150
|
|
|
100
151
|
getTranslationFiles() {
|
|
@@ -111,15 +162,38 @@ export default async function pluginContentBlog(
|
|
|
111
162
|
blogTitle,
|
|
112
163
|
blogSidebarTitle,
|
|
113
164
|
pageBasePath,
|
|
165
|
+
authorsBasePath,
|
|
166
|
+
authorsMapPath,
|
|
114
167
|
} = options;
|
|
115
168
|
|
|
116
169
|
const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
|
|
117
170
|
const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
|
|
118
|
-
|
|
171
|
+
|
|
172
|
+
const authorsMap = await getAuthorsMap({
|
|
173
|
+
contentPaths,
|
|
174
|
+
authorsMapPath,
|
|
175
|
+
authorsBaseRoutePath: normalizeUrl([
|
|
176
|
+
baseUrl,
|
|
177
|
+
routeBasePath,
|
|
178
|
+
authorsBasePath,
|
|
179
|
+
]),
|
|
180
|
+
});
|
|
181
|
+
checkAuthorsMapPermalinkCollisions(authorsMap);
|
|
182
|
+
|
|
183
|
+
let blogPosts = await generateBlogPosts(
|
|
184
|
+
contentPaths,
|
|
185
|
+
context,
|
|
186
|
+
options,
|
|
187
|
+
authorsMap,
|
|
188
|
+
);
|
|
119
189
|
blogPosts = await applyProcessBlogPosts({
|
|
120
190
|
blogPosts,
|
|
121
191
|
processBlogPosts: options.processBlogPosts,
|
|
122
192
|
});
|
|
193
|
+
reportUntruncatedBlogPosts({
|
|
194
|
+
blogPosts,
|
|
195
|
+
onUntruncatedBlogPosts: options.onUntruncatedBlogPosts,
|
|
196
|
+
});
|
|
123
197
|
const listedBlogPosts = blogPosts.filter(shouldBeListed);
|
|
124
198
|
|
|
125
199
|
if (!blogPosts.length) {
|
|
@@ -129,6 +203,7 @@ export default async function pluginContentBlog(
|
|
|
129
203
|
blogListPaginated: [],
|
|
130
204
|
blogTags: {},
|
|
131
205
|
blogTagsListPath,
|
|
206
|
+
authorsMap,
|
|
132
207
|
};
|
|
133
208
|
}
|
|
134
209
|
|
|
@@ -177,10 +252,13 @@ export default async function pluginContentBlog(
|
|
|
177
252
|
blogListPaginated,
|
|
178
253
|
blogTags,
|
|
179
254
|
blogTagsListPath,
|
|
255
|
+
authorsMap,
|
|
180
256
|
};
|
|
181
257
|
},
|
|
182
258
|
|
|
183
259
|
async contentLoaded({content, actions}) {
|
|
260
|
+
sourceToPermalinkHelper.update(content);
|
|
261
|
+
|
|
184
262
|
await createAllRoutes({
|
|
185
263
|
baseUrl,
|
|
186
264
|
content,
|
|
@@ -194,32 +272,92 @@ export default async function pluginContentBlog(
|
|
|
194
272
|
return translateContent(content, translationFiles);
|
|
195
273
|
},
|
|
196
274
|
|
|
197
|
-
configureWebpack(
|
|
275
|
+
configureWebpack() {
|
|
198
276
|
const {
|
|
199
277
|
admonitions,
|
|
200
278
|
rehypePlugins,
|
|
201
279
|
remarkPlugins,
|
|
280
|
+
recmaPlugins,
|
|
202
281
|
truncateMarker,
|
|
203
282
|
beforeDefaultRemarkPlugins,
|
|
204
283
|
beforeDefaultRehypePlugins,
|
|
205
284
|
} = options;
|
|
206
285
|
|
|
207
|
-
const markdownLoaderOptions: BlogMarkdownLoaderOptions = {
|
|
208
|
-
siteDir,
|
|
209
|
-
contentPaths,
|
|
210
|
-
truncateMarker,
|
|
211
|
-
sourceToPermalink: getSourceToPermalink(content.blogPosts),
|
|
212
|
-
onBrokenMarkdownLink: (brokenMarkdownLink) => {
|
|
213
|
-
if (onBrokenMarkdownLinks === 'ignore') {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
logger.report(
|
|
217
|
-
onBrokenMarkdownLinks,
|
|
218
|
-
)`Blog markdown link couldn't be resolved: (url=${brokenMarkdownLink.link}) in path=${brokenMarkdownLink.filePath}`;
|
|
219
|
-
},
|
|
220
|
-
};
|
|
221
|
-
|
|
222
286
|
const contentDirs = getContentPathList(contentPaths);
|
|
287
|
+
|
|
288
|
+
function createMDXLoader(): RuleSetUseItem {
|
|
289
|
+
const loaderOptions: MDXLoaderOptions = {
|
|
290
|
+
admonitions,
|
|
291
|
+
remarkPlugins,
|
|
292
|
+
rehypePlugins,
|
|
293
|
+
recmaPlugins,
|
|
294
|
+
beforeDefaultRemarkPlugins: [
|
|
295
|
+
footnoteIDFixer,
|
|
296
|
+
...beforeDefaultRemarkPlugins,
|
|
297
|
+
],
|
|
298
|
+
beforeDefaultRehypePlugins,
|
|
299
|
+
staticDirs: siteConfig.staticDirectories.map((dir) =>
|
|
300
|
+
path.resolve(siteDir, dir),
|
|
301
|
+
),
|
|
302
|
+
siteDir,
|
|
303
|
+
isMDXPartial: createAbsoluteFilePathMatcher(
|
|
304
|
+
options.exclude,
|
|
305
|
+
contentDirs,
|
|
306
|
+
),
|
|
307
|
+
metadataPath: (mdxPath: string) => {
|
|
308
|
+
// Note that metadataPath must be the same/in-sync as
|
|
309
|
+
// the path from createData for each MDX.
|
|
310
|
+
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
|
311
|
+
return path.join(dataDir, `${docuHash(aliasedPath)}.json`);
|
|
312
|
+
},
|
|
313
|
+
// For blog posts a title in markdown is always removed
|
|
314
|
+
// Blog posts title are rendered separately
|
|
315
|
+
removeContentTitle: true,
|
|
316
|
+
// Assets allow to convert some relative images paths to
|
|
317
|
+
// require() calls
|
|
318
|
+
// @ts-expect-error: TODO fix typing issue
|
|
319
|
+
createAssets: ({
|
|
320
|
+
frontMatter,
|
|
321
|
+
metadata,
|
|
322
|
+
}: {
|
|
323
|
+
frontMatter: BlogPostFrontMatter;
|
|
324
|
+
metadata: BlogPostMetadata;
|
|
325
|
+
}): Assets => ({
|
|
326
|
+
image: frontMatter.image,
|
|
327
|
+
authorsImageUrls: metadata.authors.map((author) => author.imageURL),
|
|
328
|
+
}),
|
|
329
|
+
markdownConfig: siteConfig.markdown,
|
|
330
|
+
resolveMarkdownLink: ({linkPathname, sourceFilePath}) => {
|
|
331
|
+
const permalink = resolveMarkdownLinkPathname(linkPathname, {
|
|
332
|
+
sourceFilePath,
|
|
333
|
+
sourceToPermalink: sourceToPermalinkHelper.get(),
|
|
334
|
+
siteDir,
|
|
335
|
+
contentPaths,
|
|
336
|
+
});
|
|
337
|
+
if (permalink === null) {
|
|
338
|
+
logger.report(
|
|
339
|
+
onBrokenMarkdownLinks,
|
|
340
|
+
)`Blog markdown link couldn't be resolved: (url=${linkPathname}) in source file path=${sourceFilePath}`;
|
|
341
|
+
}
|
|
342
|
+
return permalink;
|
|
343
|
+
},
|
|
344
|
+
};
|
|
345
|
+
return {
|
|
346
|
+
loader: require.resolve('@docusaurus/mdx-loader'),
|
|
347
|
+
options: loaderOptions,
|
|
348
|
+
};
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function createBlogMarkdownLoader(): RuleSetUseItem {
|
|
352
|
+
const loaderOptions: BlogMarkdownLoaderOptions = {
|
|
353
|
+
truncateMarker,
|
|
354
|
+
};
|
|
355
|
+
return {
|
|
356
|
+
loader: path.resolve(__dirname, './markdownLoader.js'),
|
|
357
|
+
options: loaderOptions,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
223
361
|
return {
|
|
224
362
|
resolve: {
|
|
225
363
|
alias: {
|
|
@@ -233,61 +371,7 @@ export default async function pluginContentBlog(
|
|
|
233
371
|
include: contentDirs
|
|
234
372
|
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
|
|
235
373
|
.map(addTrailingPathSeparator),
|
|
236
|
-
use: [
|
|
237
|
-
{
|
|
238
|
-
loader: require.resolve('@docusaurus/mdx-loader'),
|
|
239
|
-
options: {
|
|
240
|
-
admonitions,
|
|
241
|
-
remarkPlugins,
|
|
242
|
-
rehypePlugins,
|
|
243
|
-
beforeDefaultRemarkPlugins: [
|
|
244
|
-
footnoteIDFixer,
|
|
245
|
-
...beforeDefaultRemarkPlugins,
|
|
246
|
-
],
|
|
247
|
-
beforeDefaultRehypePlugins,
|
|
248
|
-
staticDirs: siteConfig.staticDirectories.map((dir) =>
|
|
249
|
-
path.resolve(siteDir, dir),
|
|
250
|
-
),
|
|
251
|
-
siteDir,
|
|
252
|
-
isMDXPartial: createAbsoluteFilePathMatcher(
|
|
253
|
-
options.exclude,
|
|
254
|
-
contentDirs,
|
|
255
|
-
),
|
|
256
|
-
metadataPath: (mdxPath: string) => {
|
|
257
|
-
// Note that metadataPath must be the same/in-sync as
|
|
258
|
-
// the path from createData for each MDX.
|
|
259
|
-
const aliasedPath = aliasedSitePath(mdxPath, siteDir);
|
|
260
|
-
return path.join(
|
|
261
|
-
dataDir,
|
|
262
|
-
`${docuHash(aliasedPath)}.json`,
|
|
263
|
-
);
|
|
264
|
-
},
|
|
265
|
-
// For blog posts a title in markdown is always removed
|
|
266
|
-
// Blog posts title are rendered separately
|
|
267
|
-
removeContentTitle: true,
|
|
268
|
-
|
|
269
|
-
// Assets allow to convert some relative images paths to
|
|
270
|
-
// require() calls
|
|
271
|
-
createAssets: ({
|
|
272
|
-
frontMatter,
|
|
273
|
-
metadata,
|
|
274
|
-
}: {
|
|
275
|
-
frontMatter: BlogPostFrontMatter;
|
|
276
|
-
metadata: BlogPostMetadata;
|
|
277
|
-
}): Assets => ({
|
|
278
|
-
image: frontMatter.image,
|
|
279
|
-
authorsImageUrls: metadata.authors.map(
|
|
280
|
-
(author) => author.imageURL,
|
|
281
|
-
),
|
|
282
|
-
}),
|
|
283
|
-
markdownConfig: siteConfig.markdown,
|
|
284
|
-
},
|
|
285
|
-
},
|
|
286
|
-
{
|
|
287
|
-
loader: path.resolve(__dirname, './markdownLoader.js'),
|
|
288
|
-
options: markdownLoaderOptions,
|
|
289
|
-
},
|
|
290
|
-
].filter(Boolean),
|
|
374
|
+
use: [createMDXLoader(), createBlogMarkdownLoader()],
|
|
291
375
|
},
|
|
292
376
|
],
|
|
293
377
|
},
|
|
@@ -295,73 +379,34 @@ export default async function pluginContentBlog(
|
|
|
295
379
|
},
|
|
296
380
|
|
|
297
381
|
async postBuild({outDir, content}) {
|
|
298
|
-
if (
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
382
|
+
if (
|
|
383
|
+
!content.blogPosts.length ||
|
|
384
|
+
!options.feedOptions.type ||
|
|
385
|
+
isBlogFeedDisabledBecauseOfHashRouter
|
|
386
|
+
) {
|
|
303
387
|
return;
|
|
304
388
|
}
|
|
389
|
+
|
|
305
390
|
await createBlogFeedFiles({
|
|
306
|
-
blogPosts,
|
|
391
|
+
blogPosts: content.blogPosts,
|
|
307
392
|
options,
|
|
308
393
|
outDir,
|
|
309
394
|
siteConfig,
|
|
310
395
|
locale: currentLocale,
|
|
396
|
+
contentPaths,
|
|
311
397
|
});
|
|
312
398
|
},
|
|
313
399
|
|
|
314
400
|
injectHtmlTags({content}) {
|
|
315
|
-
if (
|
|
401
|
+
if (
|
|
402
|
+
!content.blogPosts.length ||
|
|
403
|
+
!options.feedOptions.type ||
|
|
404
|
+
isBlogFeedDisabledBecauseOfHashRouter
|
|
405
|
+
) {
|
|
316
406
|
return {};
|
|
317
407
|
}
|
|
318
408
|
|
|
319
|
-
|
|
320
|
-
const feedTitle = options.feedOptions.title ?? context.siteConfig.title;
|
|
321
|
-
const feedsConfig = {
|
|
322
|
-
rss: {
|
|
323
|
-
type: 'application/rss+xml',
|
|
324
|
-
path: 'rss.xml',
|
|
325
|
-
title: `${feedTitle} RSS Feed`,
|
|
326
|
-
},
|
|
327
|
-
atom: {
|
|
328
|
-
type: 'application/atom+xml',
|
|
329
|
-
path: 'atom.xml',
|
|
330
|
-
title: `${feedTitle} Atom Feed`,
|
|
331
|
-
},
|
|
332
|
-
json: {
|
|
333
|
-
type: 'application/json',
|
|
334
|
-
path: 'feed.json',
|
|
335
|
-
title: `${feedTitle} JSON Feed`,
|
|
336
|
-
},
|
|
337
|
-
};
|
|
338
|
-
const headTags: HtmlTags = [];
|
|
339
|
-
|
|
340
|
-
feedTypes.forEach((feedType) => {
|
|
341
|
-
const {
|
|
342
|
-
type,
|
|
343
|
-
path: feedConfigPath,
|
|
344
|
-
title: feedConfigTitle,
|
|
345
|
-
} = feedsConfig[feedType];
|
|
346
|
-
|
|
347
|
-
headTags.push({
|
|
348
|
-
tagName: 'link',
|
|
349
|
-
attributes: {
|
|
350
|
-
rel: 'alternate',
|
|
351
|
-
type,
|
|
352
|
-
href: normalizeUrl([
|
|
353
|
-
baseUrl,
|
|
354
|
-
options.routeBasePath,
|
|
355
|
-
feedConfigPath,
|
|
356
|
-
]),
|
|
357
|
-
title: feedConfigTitle,
|
|
358
|
-
},
|
|
359
|
-
});
|
|
360
|
-
});
|
|
361
|
-
|
|
362
|
-
return {
|
|
363
|
-
headTags,
|
|
364
|
-
};
|
|
409
|
+
return {headTags: createFeedHtmlHeadTags({context, options})};
|
|
365
410
|
},
|
|
366
411
|
};
|
|
367
412
|
}
|
package/src/markdownLoader.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {truncate
|
|
8
|
+
import {truncate} from './blogUtils';
|
|
9
9
|
import type {BlogMarkdownLoaderOptions} from './types';
|
|
10
10
|
import type {LoaderContext} from 'webpack';
|
|
11
11
|
|
|
@@ -13,23 +13,19 @@ export default function markdownLoader(
|
|
|
13
13
|
this: LoaderContext<BlogMarkdownLoaderOptions>,
|
|
14
14
|
source: string,
|
|
15
15
|
): void {
|
|
16
|
-
const filePath = this.resourcePath;
|
|
17
16
|
const fileString = source;
|
|
18
17
|
const callback = this.async();
|
|
19
18
|
const markdownLoaderOptions = this.getOptions();
|
|
20
19
|
|
|
21
20
|
// Linkify blog posts
|
|
22
|
-
let finalContent =
|
|
23
|
-
fileString,
|
|
24
|
-
filePath,
|
|
25
|
-
...markdownLoaderOptions,
|
|
26
|
-
});
|
|
21
|
+
let finalContent = fileString;
|
|
27
22
|
|
|
28
23
|
// Truncate content if requested (e.g: file.md?truncated=true).
|
|
29
24
|
const truncated: boolean | undefined = this.resourceQuery
|
|
30
25
|
? !!new URLSearchParams(this.resourceQuery.slice(1)).get('truncated')
|
|
31
26
|
: undefined;
|
|
32
27
|
|
|
28
|
+
// TODO truncate with the AST instead of the string ?
|
|
33
29
|
if (truncated) {
|
|
34
30
|
finalContent = truncate(finalContent, markdownLoaderOptions.truncateMarker);
|
|
35
31
|
}
|