feat: react router config generation for docs

This commit is contained in:
endiliey 2018-08-08 00:39:17 +08:00
parent f9bc0ff7b8
commit 9e7729ad74
5 changed files with 124 additions and 103 deletions

View file

@ -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;

View file

@ -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;

View file

@ -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
View 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
View 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
};