mirror of
https://github.com/facebook/docusaurus.git
synced 2025-04-30 10:48:05 +02:00
* refactor(v2): shift markdown loader into plugin * fix(v2): build command configure webpack * temporary fix for failing test
163 lines
4.7 KiB
JavaScript
163 lines
4.7 KiB
JavaScript
/**
|
|
* Copyright (c) 2017-present, Facebook, Inc.
|
|
*
|
|
* This source code is licensed under the MIT license found in the
|
|
* LICENSE file in the root directory of this source tree.
|
|
*/
|
|
|
|
const globby = require('globby');
|
|
const path = require('path');
|
|
const fs = require('fs-extra');
|
|
const {parse, idx, normalizeUrl, generate} = require('@docusaurus/utils');
|
|
|
|
// TODO: Use a better slugify function that doesn't rely on a specific file extension.
|
|
function fileToUrl(fileName) {
|
|
return fileName
|
|
.replace('-', '/')
|
|
.replace('-', '/')
|
|
.replace('-', '/')
|
|
.replace(/\.mdx?$/, '');
|
|
}
|
|
|
|
const DEFAULT_OPTIONS = {
|
|
metadataKey: 'blogMetadata',
|
|
metadataFileName: 'blogMetadata.json',
|
|
path: 'blog', // Path to data on filesystem, relative to site dir.
|
|
routeBasePath: 'blog', // URL Route.
|
|
include: ['*.md', '*.mdx'], // Extensions to include.
|
|
pageCount: 10, // How many entries per page.
|
|
blogPageComponent: '@theme/BlogPage',
|
|
blogPostComponent: '@theme/BlogPost',
|
|
};
|
|
|
|
const TRUNCATE_MARKER = /<!--\s*truncate\s*-->/;
|
|
|
|
class DocusaurusPluginContentBlog {
|
|
constructor(opts, context) {
|
|
this.options = {...DEFAULT_OPTIONS, ...opts};
|
|
this.context = context;
|
|
this.contentPath = path.resolve(this.context.siteDir, this.options.path);
|
|
}
|
|
|
|
getName() {
|
|
return 'docusaurus-plugin-content-blog';
|
|
}
|
|
|
|
getPathsToWatch() {
|
|
return [this.contentPath];
|
|
}
|
|
|
|
// Fetches blog contents and returns metadata for the contents.
|
|
async loadContent() {
|
|
const {pageCount, include, routeBasePath} = this.options;
|
|
const {env, generatedFilesDir, siteConfig} = this.context;
|
|
const blogDir = this.contentPath;
|
|
|
|
const {baseUrl} = siteConfig;
|
|
const blogFiles = await globby(include, {
|
|
cwd: blogDir,
|
|
});
|
|
|
|
// Prepare metadata container.
|
|
const blogMetadata = [];
|
|
|
|
// Language for each blog page.
|
|
const defaultLangTag = idx(env, ['translation', 'defaultLanguage', 'tag']);
|
|
|
|
await Promise.all(
|
|
blogFiles.map(async relativeSource => {
|
|
const source = path.join(blogDir, relativeSource);
|
|
|
|
const blogFileName = path.basename(relativeSource);
|
|
// Extract, YYYY, MM, DD from the file name.
|
|
const filePathDateArr = blogFileName.split('-');
|
|
const date = new Date(
|
|
`${filePathDateArr[0]}-${filePathDateArr[1]}-${
|
|
filePathDateArr[2]
|
|
}T06:00:00.000Z`,
|
|
);
|
|
|
|
const fileString = await fs.readFile(source, 'utf-8');
|
|
const {metadata: rawMetadata, content} = parse(fileString);
|
|
|
|
let truncatedSource;
|
|
const isTruncated = TRUNCATE_MARKER.test(content);
|
|
if (isTruncated) {
|
|
const pluginContentDir = path.join(generatedFilesDir, this.getName());
|
|
await generate(
|
|
pluginContentDir,
|
|
blogFileName,
|
|
content.split(TRUNCATE_MARKER)[0],
|
|
);
|
|
truncatedSource = path.join(pluginContentDir, blogFileName);
|
|
}
|
|
|
|
const metadata = {
|
|
permalink: normalizeUrl([
|
|
baseUrl,
|
|
routeBasePath,
|
|
fileToUrl(blogFileName),
|
|
]),
|
|
source,
|
|
truncatedSource,
|
|
...rawMetadata,
|
|
date,
|
|
language: defaultLangTag,
|
|
};
|
|
blogMetadata.push(metadata);
|
|
}),
|
|
);
|
|
blogMetadata.sort((a, b) => a.date - b.date);
|
|
|
|
// Blog page handling. Example: `/blog`, `/blog/page1`, `/blog/page2`
|
|
const numOfBlog = blogMetadata.length;
|
|
const numberOfPage = Math.ceil(numOfBlog / pageCount);
|
|
const basePageUrl = path.join(baseUrl, routeBasePath);
|
|
|
|
// eslint-disable-next-line
|
|
for (let page = 0; page < numberOfPage; page++) {
|
|
blogMetadata.push({
|
|
permalink: normalizeUrl([
|
|
basePageUrl,
|
|
`${page > 0 ? `page${page + 1}` : ''}`,
|
|
]),
|
|
language: defaultLangTag,
|
|
isBlogPage: true,
|
|
posts: blogMetadata.slice(page * pageCount, (page + 1) * pageCount),
|
|
});
|
|
}
|
|
|
|
return blogMetadata;
|
|
}
|
|
|
|
async contentLoaded({content, actions}) {
|
|
const {blogPageComponent, blogPostComponent} = this.options;
|
|
const {addRoute} = actions;
|
|
content.forEach(metadataItem => {
|
|
const {isBlogPage, permalink} = metadataItem;
|
|
if (isBlogPage) {
|
|
addRoute({
|
|
path: permalink,
|
|
component: blogPageComponent,
|
|
metadata: metadataItem,
|
|
modules: metadataItem.posts.map(
|
|
post => post.truncatedSource || post.source,
|
|
),
|
|
});
|
|
return;
|
|
}
|
|
|
|
addRoute({
|
|
path: permalink,
|
|
component: blogPostComponent,
|
|
metadata: metadataItem,
|
|
modules: [metadataItem.source],
|
|
});
|
|
});
|
|
}
|
|
|
|
// TODO: Add configureWebpack plugin to read Markdown. Currently it's using
|
|
// the docs plugin's markdown loader.
|
|
}
|
|
|
|
module.exports = DocusaurusPluginContentBlog;
|