@docusaurus/plugin-content-blog 3.9.1 → 3.9.2-alpha.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.
@@ -4,6 +4,7 @@
4
4
  * This source code is licensed under the MIT license found in the
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
+ import type { TagsFile } from '@docusaurus/utils';
7
8
  import type { LoadContext } from '@docusaurus/types';
8
9
  import type { AuthorsMap, PluginOptions, BlogPost, BlogTags, BlogPaginated } from '@docusaurus/plugin-content-blog';
9
10
  import type { BlogContentPaths } from './types';
@@ -34,7 +35,7 @@ type ParsedBlogFileName = {
34
35
  slug: string;
35
36
  };
36
37
  export declare function parseBlogFileName(blogSourceRelative: string): ParsedBlogFileName;
37
- export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions, authorsMap?: AuthorsMap): Promise<BlogPost[]>;
38
+ export declare function generateBlogPosts(contentPaths: BlogContentPaths, context: LoadContext, options: PluginOptions, tagsFile: TagsFile | null, authorsMap?: AuthorsMap): Promise<BlogPost[]>;
38
39
  export declare function applyProcessBlogPosts({ blogPosts, processBlogPosts, }: {
39
40
  blogPosts: BlogPost[];
40
41
  processBlogPosts: PluginOptions['processBlogPosts'];
package/lib/blogUtils.js CHANGED
@@ -20,7 +20,6 @@ const path_1 = tslib_1.__importDefault(require("path"));
20
20
  const lodash_1 = tslib_1.__importDefault(require("lodash"));
21
21
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
22
22
  const utils_1 = require("@docusaurus/utils");
23
- const utils_validation_1 = require("@docusaurus/utils-validation");
24
23
  const frontMatter_1 = require("./frontMatter");
25
24
  const authors_1 = require("./authors");
26
25
  const authorsProblems_1 = require("./authorsProblems");
@@ -132,7 +131,7 @@ async function parseBlogPostMarkdownFile({ filePath, parseFrontMatter, }) {
132
131
  }
133
132
  const defaultReadingTime = ({ content, locale, options }) => (0, readingTime_1.calculateReadingTime)(content, locale, options);
134
133
  async function processBlogSourceFile(blogSourceRelative, contentPaths, context, options, tagsFile, authorsMap) {
135
- const { siteConfig: { baseUrl, markdown: { parseFrontMatter }, }, siteDir, i18n, } = context;
134
+ const { siteConfig: { baseUrl, markdown: { parseFrontMatter }, future: { experimental_vcs: vcs }, }, siteDir, i18n, } = context;
136
135
  const { routeBasePath, tagsBasePath: tagsRouteBasePath, truncateMarker, showReadingTime, editUrl, } = options;
137
136
  // Lookup in localized folder in priority
138
137
  const blogDirPath = await (0, utils_1.getFolderContainingFile)((0, utils_1.getContentPathList)(contentPaths), blogSourceRelative);
@@ -142,7 +141,7 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
142
141
  parseFrontMatter,
143
142
  });
144
143
  const aliasedSource = (0, utils_1.aliasedSitePath)(blogSourceAbsolute, siteDir);
145
- const lastUpdate = await (0, utils_1.readLastUpdateData)(blogSourceAbsolute, options, frontMatter.last_update);
144
+ const lastUpdate = await (0, utils_1.readLastUpdateData)(blogSourceAbsolute, options, frontMatter.last_update, vcs);
146
145
  const draft = (0, utils_1.isDraft)({ frontMatter });
147
146
  const unlisted = (0, utils_1.isUnlisted)({ frontMatter });
148
147
  if (draft) {
@@ -165,17 +164,11 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
165
164
  else if (parsedBlogFileName.date) {
166
165
  return parsedBlogFileName.date;
167
166
  }
168
- try {
169
- const result = await (0, utils_1.getFileCommitDate)(blogSourceAbsolute, {
170
- age: 'oldest',
171
- includeAuthor: false,
172
- });
173
- return result.date;
174
- }
175
- catch (err) {
176
- logger_1.default.warn(err);
167
+ const result = await vcs.getFileCreationInfo(blogSourceAbsolute);
168
+ if (result == null) {
177
169
  return (await fs_extra_1.default.stat(blogSourceAbsolute)).birthtime;
178
170
  }
171
+ return new Date(result.timestamp);
179
172
  }
180
173
  const date = await getDate();
181
174
  const title = frontMatter.title ?? contentTitle ?? parsedBlogFileName.text;
@@ -253,7 +246,7 @@ async function processBlogSourceFile(blogSourceRelative, contentPaths, context,
253
246
  content,
254
247
  };
255
248
  }
256
- async function generateBlogPosts(contentPaths, context, options, authorsMap) {
249
+ async function generateBlogPosts(contentPaths, context, options, tagsFile, authorsMap) {
257
250
  const { include, exclude } = options;
258
251
  if (!(await fs_extra_1.default.pathExists(contentPaths.contentPath))) {
259
252
  return [];
@@ -262,7 +255,6 @@ async function generateBlogPosts(contentPaths, context, options, authorsMap) {
262
255
  cwd: contentPaths.contentPath,
263
256
  ignore: exclude,
264
257
  });
265
- const tagsFile = await (0, utils_validation_1.getTagsFile)({ contentPaths, tags: options.tags });
266
258
  async function doProcessBlogSourceFile(blogSourceFile) {
267
259
  try {
268
260
  return await processBlogSourceFile(blogSourceFile, contentPaths, context, options, tagsFile, authorsMap);
package/lib/feed.js CHANGED
@@ -116,7 +116,7 @@ async function resolveXsltFilePaths({ xsltFilePath, contentPaths, }) {
116
116
  }
117
117
  const parsedPath = path_1.default.parse(xsltAbsolutePath);
118
118
  const cssAbsolutePath = path_1.default.resolve(parsedPath.dir, `${parsedPath.name}.css`);
119
- if (!(await fs_extra_1.default.pathExists(xsltAbsolutePath))) {
119
+ if (!(await fs_extra_1.default.pathExists(cssAbsolutePath))) {
120
120
  throw new Error(logger_1.default.interpolate `Blog feed XSLT file was found at path=${path_1.default.relative(process.cwd(), xsltAbsolutePath)}
121
121
  But its expected co-located CSS file could not be found at path=${path_1.default.relative(process.cwd(), cssAbsolutePath)}
122
122
  If you want to provide a custom XSLT file, you must provide a CSS file with the exact same name.`);
package/lib/index.js CHANGED
@@ -11,6 +11,7 @@ exports.default = pluginContentBlog;
11
11
  const tslib_1 = require("tslib");
12
12
  const path_1 = tslib_1.__importDefault(require("path"));
13
13
  const logger_1 = tslib_1.__importDefault(require("@docusaurus/logger"));
14
+ const combine_promises_1 = tslib_1.__importDefault(require("combine-promises"));
14
15
  const utils_1 = require("@docusaurus/utils");
15
16
  const utils_validation_1 = require("@docusaurus/utils-validation");
16
17
  const mdx_loader_1 = require("@docusaurus/mdx-loader");
@@ -41,7 +42,7 @@ async function pluginContentBlog(context, options) {
41
42
  })
42
43
  : undefined,
43
44
  };
44
- const pluginId = options.id ?? utils_1.DEFAULT_PLUGIN_ID;
45
+ const pluginId = options.id;
45
46
  const pluginDataDirRoot = path_1.default.join(generatedFilesDir, PluginName);
46
47
  const dataDir = path_1.default.join(pluginDataDirRoot, pluginId);
47
48
  // TODO Docusaurus v4 breaking change
@@ -57,7 +58,7 @@ async function pluginContentBlog(context, options) {
57
58
  const { admonitions, rehypePlugins, remarkPlugins, recmaPlugins, truncateMarker, beforeDefaultRemarkPlugins, beforeDefaultRehypePlugins, } = options;
58
59
  const contentDirs = (0, utils_1.getContentPathList)(contentPaths);
59
60
  const mdxLoaderItem = await (0, mdx_loader_1.createMDXLoaderItem)({
60
- useCrossCompilerCache: siteConfig.future.experimental_faster.mdxCrossCompilerCache,
61
+ useCrossCompilerCache: siteConfig.future.faster.mdxCrossCompilerCache,
61
62
  admonitions,
62
63
  remarkPlugins,
63
64
  rehypePlugins,
@@ -141,18 +142,26 @@ async function pluginContentBlog(context, options) {
141
142
  const { postsPerPage: postsPerPageOption, routeBasePath, tagsBasePath, blogDescription, blogTitle, blogSidebarTitle, pageBasePath, authorsBasePath, authorsMapPath, } = options;
142
143
  const baseBlogUrl = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
143
144
  const blogTagsListPath = (0, utils_1.normalizeUrl)([baseBlogUrl, tagsBasePath]);
144
- const authorsMap = await (0, authorsMap_1.getAuthorsMap)({
145
- contentPaths,
146
- authorsMapPath,
147
- authorsBaseRoutePath: (0, utils_1.normalizeUrl)([
145
+ async function getAuthorsMapChecked() {
146
+ const result = await (0, authorsMap_1.getAuthorsMap)({
147
+ contentPaths,
148
+ authorsMapPath,
149
+ authorsBaseRoutePath: (0, utils_1.normalizeUrl)([
150
+ baseUrl,
151
+ routeBasePath,
152
+ authorsBasePath,
153
+ ]),
148
154
  baseUrl,
149
- routeBasePath,
150
- authorsBasePath,
151
- ]),
152
- baseUrl,
155
+ });
156
+ (0, authorsMap_1.checkAuthorsMapPermalinkCollisions)(result);
157
+ return result;
158
+ }
159
+ // Read all the input files in parallel
160
+ const { authorsMap, tagsFile } = await (0, combine_promises_1.default)({
161
+ authorsMap: getAuthorsMapChecked(),
162
+ tagsFile: (0, utils_validation_1.getTagsFile)({ contentPaths, tags: options.tags }),
153
163
  });
154
- (0, authorsMap_1.checkAuthorsMapPermalinkCollisions)(authorsMap);
155
- let blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options, authorsMap);
164
+ let blogPosts = await (0, blogUtils_1.generateBlogPosts)(contentPaths, context, options, tagsFile, authorsMap);
156
165
  blogPosts = await (0, blogUtils_1.applyProcessBlogPosts)({
157
166
  blogPosts,
158
167
  processBlogPosts: options.processBlogPosts,
@@ -164,9 +173,10 @@ async function pluginContentBlog(context, options) {
164
173
  const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
165
174
  if (!blogPosts.length) {
166
175
  return {
176
+ blogTitle,
177
+ blogDescription,
167
178
  blogSidebarTitle,
168
179
  blogPosts: [],
169
- blogListPaginated: [],
170
180
  blogTags: {},
171
181
  blogTagsListPath,
172
182
  authorsMap,
@@ -191,14 +201,9 @@ async function pluginContentBlog(context, options) {
191
201
  };
192
202
  }
193
203
  });
194
- const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
195
- blogPosts: listedBlogPosts,
196
- blogTitle,
197
- blogDescription,
198
- postsPerPageOption,
199
- basePageUrl: baseBlogUrl,
200
- pageBasePath,
201
- });
204
+ // TODO this is not the correct place to aggregate and paginate tags
205
+ // for reasons similar to https://github.com/facebook/docusaurus/pull/11562
206
+ // What we should do here is only read the tags file (similar to authors)
202
207
  const blogTags = (0, blogUtils_1.getBlogTags)({
203
208
  blogPosts,
204
209
  postsPerPageOption,
@@ -207,9 +212,10 @@ async function pluginContentBlog(context, options) {
207
212
  pageBasePath,
208
213
  });
209
214
  return {
215
+ blogTitle,
216
+ blogDescription,
210
217
  blogSidebarTitle,
211
218
  blogPosts,
212
- blogListPaginated,
213
219
  blogTags,
214
220
  blogTagsListPath,
215
221
  authorsMap,
package/lib/options.js CHANGED
@@ -13,6 +13,7 @@ const path_1 = tslib_1.__importDefault(require("path"));
13
13
  const utils_validation_1 = require("@docusaurus/utils-validation");
14
14
  const utils_1 = require("@docusaurus/utils");
15
15
  exports.DEFAULT_OPTIONS = {
16
+ id: utils_1.DEFAULT_PLUGIN_ID,
16
17
  feedOptions: {
17
18
  type: ['rss', 'atom'],
18
19
  copyright: '',
package/lib/routes.js CHANGED
@@ -19,15 +19,12 @@ async function createAllRoutes(param) {
19
19
  routes.forEach(param.actions.addRoute);
20
20
  }
21
21
  async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSource, }) {
22
- const { blogListComponent, blogPostComponent, blogTagsListComponent, blogAuthorsListComponent, blogAuthorsPostsComponent, blogTagsPostsComponent, blogArchiveComponent, routeBasePath, archiveBasePath, blogTitle, authorsBasePath, postsPerPage, blogDescription, } = options;
22
+ const { blogListComponent, blogPostComponent, blogTagsListComponent, blogAuthorsListComponent, blogAuthorsPostsComponent, blogTagsPostsComponent, blogArchiveComponent, routeBasePath, archiveBasePath, authorsBasePath, postsPerPage, pageBasePath, } = options;
23
23
  const pluginId = options.id;
24
24
  const { createData } = actions;
25
- const { blogSidebarTitle, blogPosts, blogListPaginated, blogTags, blogTagsListPath, authorsMap, } = content;
26
- const authorsListPath = (0, utils_1.normalizeUrl)([
27
- baseUrl,
28
- routeBasePath,
29
- authorsBasePath,
30
- ]);
25
+ const { blogTitle, blogDescription, blogSidebarTitle, blogPosts, blogTags, blogTagsListPath, authorsMap, } = content;
26
+ const blogBasePath = (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]);
27
+ const authorsListPath = (0, utils_1.normalizeUrl)([blogBasePath, authorsBasePath]);
31
28
  const listedBlogPosts = blogPosts.filter(blogUtils_1.shouldBeListed);
32
29
  const blogPostsById = lodash_1.default.keyBy(blogPosts, (post) => post.id);
33
30
  function getBlogPostById(id) {
@@ -50,7 +47,7 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
50
47
  }
51
48
  async function createBlogMetadataModule() {
52
49
  const blogMetadata = {
53
- blogBasePath: (0, utils_1.normalizeUrl)([baseUrl, routeBasePath]),
50
+ blogBasePath,
54
51
  blogTitle,
55
52
  authorsListPath,
56
53
  };
@@ -81,7 +78,7 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
81
78
  if (archiveBasePath && listedBlogPosts.length) {
82
79
  return [
83
80
  {
84
- path: (0, utils_1.normalizeUrl)([baseUrl, routeBasePath, archiveBasePath]),
81
+ path: (0, utils_1.normalizeUrl)([blogBasePath, archiveBasePath]),
85
82
  component: blogArchiveComponent,
86
83
  exact: true,
87
84
  props: {
@@ -124,6 +121,14 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
124
121
  return blogPosts.map(createBlogPostRoute);
125
122
  }
126
123
  function createBlogPostsPaginatedRoutes() {
124
+ const blogListPaginated = (0, blogUtils_1.paginateBlogPosts)({
125
+ blogPosts: listedBlogPosts,
126
+ blogTitle,
127
+ blogDescription,
128
+ postsPerPageOption: postsPerPage,
129
+ basePageUrl: blogBasePath,
130
+ pageBasePath,
131
+ });
127
132
  return blogListPaginated.map((paginated) => {
128
133
  return {
129
134
  path: paginated.metadata.permalink,
@@ -197,10 +202,14 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
197
202
  sidebar: sidebarModulePath,
198
203
  },
199
204
  props: {
200
- authors: authors.map((author) => (0, props_1.toAuthorItemProp)({
201
- author,
202
- count: blogPostsByAuthorKey[author.key]?.length ?? 0,
203
- })),
205
+ authors: authors.map((author) => {
206
+ const authorPosts = blogPostsByAuthorKey[author.key] ?? [];
207
+ const listedAuthorPosts = authorPosts.filter(blogUtils_1.shouldBeListed);
208
+ return (0, props_1.toAuthorItemProp)({
209
+ author,
210
+ count: listedAuthorPosts.length,
211
+ });
212
+ }),
204
213
  },
205
214
  context: {
206
215
  blogMetadata: blogMetadataModulePath,
@@ -209,15 +218,16 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
209
218
  }
210
219
  function createAuthorPaginatedRoute(author) {
211
220
  const authorBlogPosts = blogPostsByAuthorKey[author.key] ?? [];
221
+ const listedAuthorBlogPosts = authorBlogPosts.filter(blogUtils_1.shouldBeListed);
212
222
  if (!author.page) {
213
223
  return [];
214
224
  }
215
225
  const pages = (0, blogUtils_1.paginateBlogPosts)({
216
- blogPosts: authorBlogPosts,
226
+ blogPosts: listedAuthorBlogPosts,
217
227
  basePageUrl: author.page.permalink,
218
228
  blogDescription,
219
229
  blogTitle,
220
- pageBasePath: authorsBasePath,
230
+ pageBasePath,
221
231
  postsPerPageOption: postsPerPage,
222
232
  });
223
233
  return pages.map(({ metadata, items }) => {
@@ -230,7 +240,10 @@ async function buildAllRoutes({ baseUrl, content, actions, options, aliasedSourc
230
240
  sidebar: sidebarModulePath,
231
241
  },
232
242
  props: {
233
- author: (0, props_1.toAuthorItemProp)({ author, count: authorBlogPosts.length }),
243
+ author: (0, props_1.toAuthorItemProp)({
244
+ author,
245
+ count: listedAuthorBlogPosts.length,
246
+ }),
234
247
  listMetadata: metadata,
235
248
  },
236
249
  context: {
@@ -8,19 +8,6 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.getTranslationFiles = getTranslationFiles;
10
10
  exports.translateContent = translateContent;
11
- function translateListPage(blogListPaginated, translations) {
12
- return blogListPaginated.map((page) => {
13
- const { items, metadata } = page;
14
- return {
15
- items,
16
- metadata: {
17
- ...metadata,
18
- blogTitle: translations.title?.message ?? page.metadata.blogTitle,
19
- blogDescription: translations.description?.message ?? page.metadata.blogDescription,
20
- },
21
- };
22
- });
23
- }
24
11
  function getTranslationFiles(options) {
25
12
  return [
26
13
  {
@@ -43,10 +30,11 @@ function getTranslationFiles(options) {
43
30
  ];
44
31
  }
45
32
  function translateContent(content, translationFiles) {
46
- const { content: optionsTranslations } = translationFiles[0];
33
+ const { content: translations } = translationFiles[0];
47
34
  return {
48
35
  ...content,
49
- blogSidebarTitle: optionsTranslations['sidebar.title']?.message ?? content.blogSidebarTitle,
50
- blogListPaginated: translateListPage(content.blogListPaginated, optionsTranslations),
36
+ blogTitle: translations.title?.message ?? content.blogTitle,
37
+ blogDescription: translations.description?.message ?? content.blogDescription,
38
+ blogSidebarTitle: translations['sidebar.title']?.message ?? content.blogSidebarTitle,
51
39
  };
52
40
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/plugin-content-blog",
3
- "version": "3.9.1",
3
+ "version": "3.9.2-alpha.0",
4
4
  "description": "Blog plugin for Docusaurus.",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/plugin-content-blog.d.ts",
@@ -31,15 +31,16 @@
31
31
  },
32
32
  "license": "MIT",
33
33
  "dependencies": {
34
- "@docusaurus/core": "3.9.1",
35
- "@docusaurus/logger": "3.9.1",
36
- "@docusaurus/mdx-loader": "3.9.1",
37
- "@docusaurus/theme-common": "3.9.1",
38
- "@docusaurus/types": "3.9.1",
39
- "@docusaurus/utils": "3.9.1",
40
- "@docusaurus/utils-common": "3.9.1",
41
- "@docusaurus/utils-validation": "3.9.1",
34
+ "@docusaurus/core": "3.9.2-alpha.0",
35
+ "@docusaurus/logger": "3.9.2-alpha.0",
36
+ "@docusaurus/mdx-loader": "3.9.2-alpha.0",
37
+ "@docusaurus/theme-common": "3.9.2-alpha.0",
38
+ "@docusaurus/types": "3.9.2-alpha.0",
39
+ "@docusaurus/utils": "3.9.2-alpha.0",
40
+ "@docusaurus/utils-common": "3.9.2-alpha.0",
41
+ "@docusaurus/utils-validation": "3.9.2-alpha.0",
42
42
  "cheerio": "1.0.0-rc.12",
43
+ "combine-promises": "^1.1.0",
43
44
  "feed": "^4.2.2",
44
45
  "fs-extra": "^11.1.1",
45
46
  "lodash": "^4.17.21",
@@ -62,5 +63,5 @@
62
63
  "@total-typescript/shoehorn": "^0.1.2",
63
64
  "tree-node-cli": "^1.6.0"
64
65
  },
65
- "gitHead": "c0dd59f0e712f85b6053c59e46b0514b5d2d1414"
66
+ "gitHead": "27626cdd7a102277935f10cc4d8d3f93e211eafe"
66
67
  }
package/src/blogUtils.ts CHANGED
@@ -19,7 +19,6 @@ import {
19
19
  Globby,
20
20
  groupTaggedItems,
21
21
  getTagVisibility,
22
- getFileCommitDate,
23
22
  getContentPathList,
24
23
  isUnlisted,
25
24
  isDraft,
@@ -27,7 +26,7 @@ import {
27
26
  normalizeTags,
28
27
  aliasedSitePathToRelativePath,
29
28
  } from '@docusaurus/utils';
30
- import {getTagsFile} from '@docusaurus/utils-validation';
29
+
31
30
  import {validateBlogPostFrontMatter} from './frontMatter';
32
31
  import {getBlogPostAuthors} from './authors';
33
32
  import {reportAuthorsProblems} from './authorsProblems';
@@ -225,6 +224,7 @@ async function processBlogSourceFile(
225
224
  siteConfig: {
226
225
  baseUrl,
227
226
  markdown: {parseFrontMatter},
227
+ future: {experimental_vcs: vcs},
228
228
  },
229
229
  siteDir,
230
230
  i18n,
@@ -257,6 +257,7 @@ async function processBlogSourceFile(
257
257
  blogSourceAbsolute,
258
258
  options,
259
259
  frontMatter.last_update,
260
+ vcs,
260
261
  );
261
262
 
262
263
  const draft = isDraft({frontMatter});
@@ -285,17 +286,11 @@ async function processBlogSourceFile(
285
286
  return parsedBlogFileName.date;
286
287
  }
287
288
 
288
- try {
289
- const result = await getFileCommitDate(blogSourceAbsolute, {
290
- age: 'oldest',
291
- includeAuthor: false,
292
- });
293
-
294
- return result.date;
295
- } catch (err) {
296
- logger.warn(err);
289
+ const result = await vcs.getFileCreationInfo(blogSourceAbsolute);
290
+ if (result == null) {
297
291
  return (await fs.stat(blogSourceAbsolute)).birthtime;
298
292
  }
293
+ return new Date(result.timestamp);
299
294
  }
300
295
 
301
296
  const date = await getDate();
@@ -393,6 +388,7 @@ export async function generateBlogPosts(
393
388
  contentPaths: BlogContentPaths,
394
389
  context: LoadContext,
395
390
  options: PluginOptions,
391
+ tagsFile: TagsFile | null,
396
392
  authorsMap?: AuthorsMap,
397
393
  ): Promise<BlogPost[]> {
398
394
  const {include, exclude} = options;
@@ -406,8 +402,6 @@ export async function generateBlogPosts(
406
402
  ignore: exclude,
407
403
  });
408
404
 
409
- const tagsFile = await getTagsFile({contentPaths, tags: options.tags});
410
-
411
405
  async function doProcessBlogSourceFile(blogSourceFile: string) {
412
406
  try {
413
407
  return await processBlogSourceFile(
package/src/feed.ts CHANGED
@@ -213,7 +213,7 @@ async function resolveXsltFilePaths({
213
213
  parsedPath.dir,
214
214
  `${parsedPath.name}.css`,
215
215
  );
216
- if (!(await fs.pathExists(xsltAbsolutePath))) {
216
+ if (!(await fs.pathExists(cssAbsolutePath))) {
217
217
  throw new Error(
218
218
  logger.interpolate`Blog feed XSLT file was found at path=${path.relative(
219
219
  process.cwd(),
package/src/index.ts CHANGED
@@ -7,6 +7,8 @@
7
7
 
8
8
  import path from 'path';
9
9
  import logger from '@docusaurus/logger';
10
+ import combinePromises from 'combine-promises';
11
+
10
12
  import {
11
13
  normalizeUrl,
12
14
  docuHash,
@@ -17,15 +19,16 @@ import {
17
19
  createAbsoluteFilePathMatcher,
18
20
  getContentPathList,
19
21
  getDataFilePath,
20
- DEFAULT_PLUGIN_ID,
21
22
  resolveMarkdownLinkPathname,
22
23
  getLocaleConfig,
23
24
  } from '@docusaurus/utils';
24
- import {getTagsFilePathsToWatch} from '@docusaurus/utils-validation';
25
+ import {
26
+ getTagsFilePathsToWatch,
27
+ getTagsFile,
28
+ } from '@docusaurus/utils-validation';
25
29
  import {createMDXLoaderItem} from '@docusaurus/mdx-loader';
26
30
  import {
27
31
  getBlogTags,
28
- paginateBlogPosts,
29
32
  shouldBeListed,
30
33
  applyProcessBlogPosts,
31
34
  generateBlogPosts,
@@ -45,7 +48,6 @@ import type {
45
48
  Assets,
46
49
  BlogTags,
47
50
  BlogContent,
48
- BlogPaginated,
49
51
  } from '@docusaurus/plugin-content-blog';
50
52
  import type {RuleSetRule, RuleSetUseItem} from 'webpack';
51
53
 
@@ -85,7 +87,7 @@ export default async function pluginContentBlog(
85
87
  })
86
88
  : undefined,
87
89
  };
88
- const pluginId = options.id ?? DEFAULT_PLUGIN_ID;
90
+ const pluginId = options.id;
89
91
 
90
92
  const pluginDataDirRoot = path.join(generatedFilesDir, PluginName);
91
93
  const dataDir = path.join(pluginDataDirRoot, pluginId);
@@ -116,8 +118,7 @@ export default async function pluginContentBlog(
116
118
  const contentDirs = getContentPathList(contentPaths);
117
119
 
118
120
  const mdxLoaderItem = await createMDXLoaderItem({
119
- useCrossCompilerCache:
120
- siteConfig.future.experimental_faster.mdxCrossCompilerCache,
121
+ useCrossCompilerCache: siteConfig.future.faster.mdxCrossCompilerCache,
121
122
  admonitions,
122
123
  remarkPlugins,
123
124
  rehypePlugins,
@@ -230,22 +231,32 @@ export default async function pluginContentBlog(
230
231
  const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]);
231
232
  const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]);
232
233
 
233
- const authorsMap = await getAuthorsMap({
234
- contentPaths,
235
- authorsMapPath,
236
- authorsBaseRoutePath: normalizeUrl([
234
+ async function getAuthorsMapChecked() {
235
+ const result = await getAuthorsMap({
236
+ contentPaths,
237
+ authorsMapPath,
238
+ authorsBaseRoutePath: normalizeUrl([
239
+ baseUrl,
240
+ routeBasePath,
241
+ authorsBasePath,
242
+ ]),
237
243
  baseUrl,
238
- routeBasePath,
239
- authorsBasePath,
240
- ]),
241
- baseUrl,
244
+ });
245
+ checkAuthorsMapPermalinkCollisions(result);
246
+ return result;
247
+ }
248
+
249
+ // Read all the input files in parallel
250
+ const {authorsMap, tagsFile} = await combinePromises({
251
+ authorsMap: getAuthorsMapChecked(),
252
+ tagsFile: getTagsFile({contentPaths, tags: options.tags}),
242
253
  });
243
- checkAuthorsMapPermalinkCollisions(authorsMap);
244
254
 
245
255
  let blogPosts = await generateBlogPosts(
246
256
  contentPaths,
247
257
  context,
248
258
  options,
259
+ tagsFile,
249
260
  authorsMap,
250
261
  );
251
262
  blogPosts = await applyProcessBlogPosts({
@@ -260,9 +271,10 @@ export default async function pluginContentBlog(
260
271
 
261
272
  if (!blogPosts.length) {
262
273
  return {
274
+ blogTitle,
275
+ blogDescription,
263
276
  blogSidebarTitle,
264
277
  blogPosts: [],
265
- blogListPaginated: [],
266
278
  blogTags: {},
267
279
  blogTagsListPath,
268
280
  authorsMap,
@@ -291,15 +303,9 @@ export default async function pluginContentBlog(
291
303
  }
292
304
  });
293
305
 
294
- const blogListPaginated: BlogPaginated[] = paginateBlogPosts({
295
- blogPosts: listedBlogPosts,
296
- blogTitle,
297
- blogDescription,
298
- postsPerPageOption,
299
- basePageUrl: baseBlogUrl,
300
- pageBasePath,
301
- });
302
-
306
+ // TODO this is not the correct place to aggregate and paginate tags
307
+ // for reasons similar to https://github.com/facebook/docusaurus/pull/11562
308
+ // What we should do here is only read the tags file (similar to authors)
303
309
  const blogTags: BlogTags = getBlogTags({
304
310
  blogPosts,
305
311
  postsPerPageOption,
@@ -309,9 +315,10 @@ export default async function pluginContentBlog(
309
315
  });
310
316
 
311
317
  return {
318
+ blogTitle,
319
+ blogDescription,
312
320
  blogSidebarTitle,
313
321
  blogPosts,
314
- blogListPaginated,
315
322
  blogTags,
316
323
  blogTagsListPath,
317
324
  authorsMap,
package/src/options.ts CHANGED
@@ -15,7 +15,7 @@ import {
15
15
  RouteBasePathSchema,
16
16
  URISchema,
17
17
  } from '@docusaurus/utils-validation';
18
- import {GlobExcludeDefault} from '@docusaurus/utils';
18
+ import {DEFAULT_PLUGIN_ID, GlobExcludeDefault} from '@docusaurus/utils';
19
19
  import type {
20
20
  PluginOptions,
21
21
  Options,
@@ -25,6 +25,7 @@ import type {
25
25
  import type {OptionValidationContext} from '@docusaurus/types';
26
26
 
27
27
  export const DEFAULT_OPTIONS: PluginOptions = {
28
+ id: DEFAULT_PLUGIN_ID,
28
29
  feedOptions: {
29
30
  type: ['rss', 'atom'],
30
31
  copyright: '',
@@ -431,7 +431,7 @@ declare module '@docusaurus/plugin-content-blog' {
431
431
  export type PluginOptions = MDXOptions &
432
432
  TagsPluginOptions & {
433
433
  /** Plugin ID. */
434
- id?: string;
434
+ id: string;
435
435
  /**
436
436
  * Path to the blog content directory on the file system, relative to site
437
437
  * directory.
@@ -583,9 +583,10 @@ declare module '@docusaurus/plugin-content-blog' {
583
583
  export type AuthorsMap = {[authorKey: string]: AuthorWithKey};
584
584
 
585
585
  export type BlogContent = {
586
- blogSidebarTitle: string;
586
+ blogTitle: string; // for translation purposes
587
+ blogDescription: string; // for translation purposes
588
+ blogSidebarTitle: string; // for translation purposes
587
589
  blogPosts: BlogPost[];
588
- blogListPaginated: BlogPaginated[];
589
590
  blogTags: BlogTags;
590
591
  blogTagsListPath: string;
591
592
  authorsMap?: AuthorsMap;
package/src/routes.ts CHANGED
@@ -67,27 +67,24 @@ export async function buildAllRoutes({
67
67
  blogArchiveComponent,
68
68
  routeBasePath,
69
69
  archiveBasePath,
70
- blogTitle,
71
70
  authorsBasePath,
72
71
  postsPerPage,
73
- blogDescription,
72
+ pageBasePath,
74
73
  } = options;
75
- const pluginId = options.id!;
74
+ const pluginId = options.id;
76
75
  const {createData} = actions;
77
76
  const {
77
+ blogTitle,
78
+ blogDescription,
78
79
  blogSidebarTitle,
79
80
  blogPosts,
80
- blogListPaginated,
81
81
  blogTags,
82
82
  blogTagsListPath,
83
83
  authorsMap,
84
84
  } = content;
85
85
 
86
- const authorsListPath = normalizeUrl([
87
- baseUrl,
88
- routeBasePath,
89
- authorsBasePath,
90
- ]);
86
+ const blogBasePath = normalizeUrl([baseUrl, routeBasePath]);
87
+ const authorsListPath = normalizeUrl([blogBasePath, authorsBasePath]);
91
88
 
92
89
  const listedBlogPosts = blogPosts.filter(shouldBeListed);
93
90
 
@@ -119,7 +116,7 @@ export async function buildAllRoutes({
119
116
 
120
117
  async function createBlogMetadataModule() {
121
118
  const blogMetadata: BlogMetadata = {
122
- blogBasePath: normalizeUrl([baseUrl, routeBasePath]),
119
+ blogBasePath,
123
120
  blogTitle,
124
121
  authorsListPath,
125
122
  };
@@ -156,7 +153,7 @@ export async function buildAllRoutes({
156
153
  if (archiveBasePath && listedBlogPosts.length) {
157
154
  return [
158
155
  {
159
- path: normalizeUrl([baseUrl, routeBasePath, archiveBasePath]),
156
+ path: normalizeUrl([blogBasePath, archiveBasePath]),
160
157
  component: blogArchiveComponent,
161
158
  exact: true,
162
159
  props: {
@@ -210,6 +207,15 @@ export async function buildAllRoutes({
210
207
  }
211
208
 
212
209
  function createBlogPostsPaginatedRoutes(): RouteConfig[] {
210
+ const blogListPaginated = paginateBlogPosts({
211
+ blogPosts: listedBlogPosts,
212
+ blogTitle,
213
+ blogDescription,
214
+ postsPerPageOption: postsPerPage,
215
+ basePageUrl: blogBasePath,
216
+ pageBasePath,
217
+ });
218
+
213
219
  return blogListPaginated.map((paginated) => {
214
220
  return {
215
221
  path: paginated.metadata.permalink,
@@ -294,12 +300,14 @@ export async function buildAllRoutes({
294
300
  sidebar: sidebarModulePath,
295
301
  },
296
302
  props: {
297
- authors: authors.map((author) =>
298
- toAuthorItemProp({
303
+ authors: authors.map((author) => {
304
+ const authorPosts = blogPostsByAuthorKey[author.key] ?? [];
305
+ const listedAuthorPosts = authorPosts.filter(shouldBeListed);
306
+ return toAuthorItemProp({
299
307
  author,
300
- count: blogPostsByAuthorKey[author.key]?.length ?? 0,
301
- }),
302
- ),
308
+ count: listedAuthorPosts.length,
309
+ });
310
+ }),
303
311
  },
304
312
  context: {
305
313
  blogMetadata: blogMetadataModulePath,
@@ -309,16 +317,17 @@ export async function buildAllRoutes({
309
317
 
310
318
  function createAuthorPaginatedRoute(author: AuthorWithKey): RouteConfig[] {
311
319
  const authorBlogPosts = blogPostsByAuthorKey[author.key] ?? [];
320
+ const listedAuthorBlogPosts = authorBlogPosts.filter(shouldBeListed);
312
321
  if (!author.page) {
313
322
  return [];
314
323
  }
315
324
 
316
325
  const pages = paginateBlogPosts({
317
- blogPosts: authorBlogPosts,
326
+ blogPosts: listedAuthorBlogPosts,
318
327
  basePageUrl: author.page.permalink,
319
328
  blogDescription,
320
329
  blogTitle,
321
- pageBasePath: authorsBasePath,
330
+ pageBasePath,
322
331
  postsPerPageOption: postsPerPage,
323
332
  });
324
333
 
@@ -332,7 +341,10 @@ export async function buildAllRoutes({
332
341
  sidebar: sidebarModulePath,
333
342
  },
334
343
  props: {
335
- author: toAuthorItemProp({author, count: authorBlogPosts.length}),
344
+ author: toAuthorItemProp({
345
+ author,
346
+ count: listedAuthorBlogPosts.length,
347
+ }),
336
348
  listMetadata: metadata,
337
349
  },
338
350
  context: {
@@ -5,30 +5,8 @@
5
5
  * LICENSE file in the root directory of this source tree.
6
6
  */
7
7
 
8
- import type {TranslationFileContent, TranslationFile} from '@docusaurus/types';
9
- import type {
10
- PluginOptions,
11
- BlogContent,
12
- BlogPaginated,
13
- } from '@docusaurus/plugin-content-blog';
14
-
15
- function translateListPage(
16
- blogListPaginated: BlogPaginated[],
17
- translations: TranslationFileContent,
18
- ) {
19
- return blogListPaginated.map((page) => {
20
- const {items, metadata} = page;
21
- return {
22
- items,
23
- metadata: {
24
- ...metadata,
25
- blogTitle: translations.title?.message ?? page.metadata.blogTitle,
26
- blogDescription:
27
- translations.description?.message ?? page.metadata.blogDescription,
28
- },
29
- };
30
- });
31
- }
8
+ import type {TranslationFile} from '@docusaurus/types';
9
+ import type {PluginOptions, BlogContent} from '@docusaurus/plugin-content-blog';
32
10
 
33
11
  export function getTranslationFiles(options: PluginOptions): TranslationFile[] {
34
12
  return [
@@ -56,14 +34,13 @@ export function translateContent(
56
34
  content: BlogContent,
57
35
  translationFiles: TranslationFile[],
58
36
  ): BlogContent {
59
- const {content: optionsTranslations} = translationFiles[0]!;
37
+ const {content: translations} = translationFiles[0]!;
60
38
  return {
61
39
  ...content,
40
+ blogTitle: translations.title?.message ?? content.blogTitle,
41
+ blogDescription:
42
+ translations.description?.message ?? content.blogDescription,
62
43
  blogSidebarTitle:
63
- optionsTranslations['sidebar.title']?.message ?? content.blogSidebarTitle,
64
- blogListPaginated: translateListPage(
65
- content.blogListPaginated,
66
- optionsTranslations,
67
- ),
44
+ translations['sidebar.title']?.message ?? content.blogSidebarTitle,
68
45
  };
69
46
  }