mirror of
https://github.com/facebook/docusaurus.git
synced 2025-05-24 22:46:57 +02:00
feat: react router config generation for docs
This commit is contained in:
parent
f9bc0ff7b8
commit
9e7729ad74
5 changed files with 124 additions and 103 deletions
|
@ -1,47 +0,0 @@
|
||||||
const fs = require('fs-extra');
|
|
||||||
const path = require('path');
|
|
||||||
const fm = require('front-matter');
|
|
||||||
const globby = require('globby');
|
|
||||||
|
|
||||||
const indexRE = /(^|.*\/)index\.md$/i;
|
|
||||||
const mdRE = /\.md$/;
|
|
||||||
|
|
||||||
function fileToPath(file) {
|
|
||||||
if (indexRE.test(file)) {
|
|
||||||
return file.replace(indexRE, '/$1');
|
|
||||||
}
|
|
||||||
return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parse(fileString) {
|
|
||||||
if (!fm.test(fileString)) {
|
|
||||||
return {metadata: null, content: fileString};
|
|
||||||
}
|
|
||||||
const {attributes: metadata, body: content} = fm(fileString);
|
|
||||||
|
|
||||||
return {metadata, content};
|
|
||||||
}
|
|
||||||
|
|
||||||
async function loadBlog(blogDir) {
|
|
||||||
const blogFiles = await globby(['**/*.md'], {
|
|
||||||
cwd: blogDir
|
|
||||||
});
|
|
||||||
|
|
||||||
const blogDatas = await Promise.all(
|
|
||||||
blogFiles.map(async file => {
|
|
||||||
const filepath = path.resolve(blogDir, file);
|
|
||||||
const fileString = await fs.readFile(filepath, 'utf-8');
|
|
||||||
const {metadata, content} = parse(fileString);
|
|
||||||
|
|
||||||
return {
|
|
||||||
path: fileToPath(file),
|
|
||||||
content,
|
|
||||||
...metadata
|
|
||||||
};
|
|
||||||
})
|
|
||||||
);
|
|
||||||
blogDatas.sort((a, b) => b.date - a.date);
|
|
||||||
return blogDatas;
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = loadBlog;
|
|
|
@ -2,16 +2,7 @@ const fs = require('fs-extra');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const fm = require('front-matter');
|
const fm = require('front-matter');
|
||||||
const globby = require('globby');
|
const globby = require('globby');
|
||||||
|
const {encodePath, fileToPath} = require('./utils');
|
||||||
const indexRE = /(^|.*\/)index\.md$/i;
|
|
||||||
const mdRE = /\.md$/;
|
|
||||||
|
|
||||||
function fileToPath(file) {
|
|
||||||
if (indexRE.test(file)) {
|
|
||||||
return file.replace(indexRE, '/$1');
|
|
||||||
}
|
|
||||||
return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function parse(fileString) {
|
function parse(fileString) {
|
||||||
if (!fm.test(fileString)) {
|
if (!fm.test(fileString)) {
|
||||||
|
@ -22,27 +13,25 @@ function parse(fileString) {
|
||||||
return {metadata, content};
|
return {metadata, content};
|
||||||
}
|
}
|
||||||
|
|
||||||
// still TODO. still copy paste from blog logic
|
async function loadDocs(docsDir) {
|
||||||
async function loadDocs(siteDir) {
|
const docsFiles = await globby(['**/*.md'], {
|
||||||
const blogFiles = await globby(['**/*.md'], {
|
cwd: docsDir
|
||||||
cwd: siteDir
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const blogDatas = await Promise.all(
|
const docsData = await Promise.all(
|
||||||
blogFiles.map(async file => {
|
docsFiles.map(async source => {
|
||||||
const filepath = path.resolve(siteDir, file);
|
const filepath = path.resolve(docsDir, source);
|
||||||
const fileString = await fs.readFile(filepath, 'utf-8');
|
const fileString = await fs.readFile(filepath, 'utf-8');
|
||||||
const {metadata, content} = parse(fileString);
|
const {metadata} = parse(fileString);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
path: fileToPath(file),
|
path: encodePath(fileToPath(source)),
|
||||||
content,
|
source,
|
||||||
...metadata
|
...metadata
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
blogDatas.sort((a, b) => b.date - a.date);
|
return docsData;
|
||||||
return blogDatas;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = loadDocs;
|
module.exports = loadDocs;
|
||||||
|
|
|
@ -1,58 +1,51 @@
|
||||||
const fs = require('fs-extra');
|
const fs = require('fs-extra');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
const loadConfig = require('./config');
|
const loadConfig = require('./config');
|
||||||
const loadBlog = require('./blog');
|
|
||||||
const loadDocs = require('./docs');
|
const loadDocs = require('./docs');
|
||||||
const {generate} = require('../helpers');
|
const {generate} = require('./utils');
|
||||||
|
const genRoutesConfig = require('./routes');
|
||||||
|
|
||||||
module.exports = async function load(siteDir) {
|
module.exports = async function load(siteDir) {
|
||||||
// load siteConfig
|
// siteConfig
|
||||||
const siteConfig = loadConfig(siteDir);
|
const siteConfig = loadConfig(siteDir);
|
||||||
|
|
||||||
// docs
|
// docs
|
||||||
const docsRelativeDir = siteConfig.customDocsPath || 'docs';
|
const docsDir = path.resolve(
|
||||||
const docsMetadata = await loadDocs(
|
siteDir,
|
||||||
path.resolve(siteDir, '..', docsRelativeDir)
|
'..',
|
||||||
|
siteConfig.customDocsPath || 'docs'
|
||||||
);
|
);
|
||||||
|
const docsData = await loadDocs(docsDir);
|
||||||
await generate(
|
await generate(
|
||||||
'docsMetadata.js',
|
'docsData.js',
|
||||||
`${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify(
|
`export const docsData = ${JSON.stringify(docsData, null, 2)}`
|
||||||
docsMetadata,
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)};\n`
|
|
||||||
);
|
|
||||||
|
|
||||||
// blog
|
|
||||||
const blogMetadata = await loadBlog(path.resolve(siteDir, 'blog'));
|
|
||||||
await generate(
|
|
||||||
'blogMetadata.js',
|
|
||||||
`${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify(
|
|
||||||
blogMetadata,
|
|
||||||
null,
|
|
||||||
2
|
|
||||||
)};\n`
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// resolve outDir
|
// resolve outDir
|
||||||
const outDir = siteConfig.dest
|
const outDir = path.resolve(siteDir, 'build');
|
||||||
? path.resolve(siteConfig.dest)
|
|
||||||
: path.resolve(siteDir, '.munseo/dist');
|
|
||||||
|
|
||||||
// resolve the path of our app user interface layout
|
// resolve the theme
|
||||||
const uiPath =
|
const themePath =
|
||||||
!siteConfig.uiPath ||
|
siteConfig.themePath &&
|
||||||
!fs.existsSync(path.resolve(siteDir, siteConfig.uiPath))
|
fs.existsSync(path.resolve(siteDir, siteConfig.themePath))
|
||||||
? path.resolve(__dirname, '../ui')
|
? siteConfig.themePath
|
||||||
: siteConfig.uiPath;
|
: path.resolve(__dirname, '../theme');
|
||||||
|
|
||||||
const baseUrl = siteConfig.baseUrl || '/';
|
const baseUrl = siteConfig.baseUrl || '/';
|
||||||
|
|
||||||
return {
|
const props = {
|
||||||
siteConfig,
|
siteConfig,
|
||||||
siteDir,
|
siteDir,
|
||||||
|
docsDir,
|
||||||
|
docsData,
|
||||||
outDir,
|
outDir,
|
||||||
uiPath,
|
themePath,
|
||||||
baseUrl
|
baseUrl
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Generate React Router Config
|
||||||
|
const routesConfig = await genRoutesConfig(props);
|
||||||
|
await generate('routes.js', routesConfig);
|
||||||
|
|
||||||
|
return props;
|
||||||
};
|
};
|
||||||
|
|
38
lib/load/routes.js
Normal file
38
lib/load/routes.js
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
const path = require('path');
|
||||||
|
const {fileToComponentName} = require('./utils');
|
||||||
|
|
||||||
|
async function genRoutesConfig({docsData, docsDir}) {
|
||||||
|
function genDocsRoute({path: docsPath, source}) {
|
||||||
|
const componentName = fileToComponentName(source);
|
||||||
|
return `
|
||||||
|
{
|
||||||
|
path: ${JSON.stringify(docsPath)},
|
||||||
|
component: () => <Docs><${componentName} /></Docs>
|
||||||
|
}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function genDocsImport({source}) {
|
||||||
|
const filePath = path.resolve(docsDir, source);
|
||||||
|
const componentName = fileToComponentName(source);
|
||||||
|
return `import ${componentName} from ${JSON.stringify(filePath)}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
const notFoundRoute = `,
|
||||||
|
{
|
||||||
|
path: '*',
|
||||||
|
component: NotFound
|
||||||
|
}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
`import React from 'react';\n` +
|
||||||
|
`import Docs from '@theme/Docs';\n` +
|
||||||
|
`import NotFound from '@theme/NotFound';\n` +
|
||||||
|
`${docsData.map(genDocsImport).join('\n')}\n` +
|
||||||
|
`const routes = [${docsData
|
||||||
|
.map(genDocsRoute)
|
||||||
|
.join(',')}${notFoundRoute}\n];\n` +
|
||||||
|
`export default routes;\n`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = genRoutesConfig;
|
48
lib/load/utils.js
Normal file
48
lib/load/utils.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
|
||||||
|
const genPath = path.resolve(__dirname, '../core/generated');
|
||||||
|
fs.ensureDirSync(genPath);
|
||||||
|
|
||||||
|
const genCache = new Map();
|
||||||
|
async function generate(file, content) {
|
||||||
|
const cached = genCache.get(file);
|
||||||
|
if (cached !== content) {
|
||||||
|
await fs.writeFile(path.join(genPath, file), content);
|
||||||
|
genCache.set(file, content);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const indexRE = /(^|.*\/)index\.md$/i;
|
||||||
|
const mdRE = /\.md$/;
|
||||||
|
|
||||||
|
function fileToPath(file) {
|
||||||
|
if (indexRE.test(file)) {
|
||||||
|
return file.replace(indexRE, '/$1');
|
||||||
|
}
|
||||||
|
return `/${file.replace(mdRE, '').replace(/\\/g, '/')}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function encodePath(userpath) {
|
||||||
|
return userpath
|
||||||
|
.split('/')
|
||||||
|
.map(item => encodeURIComponent(item))
|
||||||
|
.join('/');
|
||||||
|
}
|
||||||
|
|
||||||
|
function fileToComponentName(file) {
|
||||||
|
let str = file.replace(/([A-Z])/g, ' $1');
|
||||||
|
if (str.length === 1) {
|
||||||
|
return str.toUpperCase();
|
||||||
|
}
|
||||||
|
str = str.replace(/^[\W_]+|[\W_]+$/g, '').toLowerCase();
|
||||||
|
str = str.charAt(0).toUpperCase() + str.slice(1);
|
||||||
|
return str.replace(/[\W_]+(\w|$)/g, (_, ch) => ch.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
encodePath,
|
||||||
|
generate,
|
||||||
|
fileToPath,
|
||||||
|
fileToComponentName
|
||||||
|
};
|
Loading…
Add table
Add a link
Reference in a new issue