From 221023fd51176cf321afd137c3e4e56da08afae7 Mon Sep 17 00:00:00 2001 From: endiliey Date: Sun, 5 Aug 2018 18:59:23 +0800 Subject: [PATCH] feat: prototype blog & docs generation on dev --- lib/core/blog/index.js | 11 +++++++ lib/core/blogPost.js | 13 -------- lib/core/devEntry.js | 29 +++++++++++------- lib/core/docs/index.js | 11 +++++++ lib/core/markdown/index.js | 4 +++ lib/loader/blog.js | 3 +- lib/loader/config.js | 2 +- lib/loader/docs.js | 47 +++++++++++++++++++++++++++++ lib/loader/index.js | 29 +++++++++++++----- lib/webpack/base.js | 4 +-- package.json | 3 ++ yarn.lock | 62 ++++++++++++++++++++++++++++++++++++++ 12 files changed, 181 insertions(+), 37 deletions(-) create mode 100644 lib/core/blog/index.js delete mode 100644 lib/core/blogPost.js create mode 100644 lib/core/docs/index.js create mode 100644 lib/loader/docs.js diff --git a/lib/core/blog/index.js b/lib/core/blog/index.js new file mode 100644 index 0000000000..f5f1bf7b69 --- /dev/null +++ b/lib/core/blog/index.js @@ -0,0 +1,11 @@ +import React from 'react'; +import MarkdownBlock from '../markdown'; + +class Docs extends React.Component { + render() { + const {content, siteConfig} = this.props; + return {content}; + } +} + +module.exports = Docs; diff --git a/lib/core/blogPost.js b/lib/core/blogPost.js deleted file mode 100644 index 0698cf6581..0000000000 --- a/lib/core/blogPost.js +++ /dev/null @@ -1,13 +0,0 @@ -import React from 'react'; -import blogDatas from '@generated/blogDatas'; - -// inner blog component for the article itself, without sidebar/header/footer -class BlogPost extends React.Component { - render() { - const {match} = this.props; - const post = blogDatas.find(blog => blog.path === match.path); - return
{post && post.content}
; - } -} - -module.exports = BlogPost; diff --git a/lib/core/devEntry.js b/lib/core/devEntry.js index 8fb024c577..ebf7322b07 100644 --- a/lib/core/devEntry.js +++ b/lib/core/devEntry.js @@ -1,8 +1,19 @@ import React from 'react'; import {render} from 'react-dom'; import {BrowserRouter, Route, Switch, Link} from 'react-router-dom'; -import blogDatas from '@generated/blogDatas'; -import BlogPost from './blogPost'; +import blogMetadata from '@generated/blogMetadata'; +import docsMetadata from '@generated/docsMetadata'; +import Blog from './blog'; +import Docs from './docs'; + +const renderBlog = props => { + const metadata = blogMetadata.find(blog => blog.path === props.match.path); + return ; +}; +const renderDocs = props => { + const metadata = docsMetadata.find(doc => doc.path === props.match.path); + return ; +}; class App extends React.Component { render() { @@ -10,17 +21,13 @@ class App extends React.Component {
- {blogDatas.map(({path}) => ( - + {blogMetadata.map(({path, content}) => ( + + ))} + {docsMetadata.map(({path}) => ( + ))} -
- {blogDatas.map(({path}) => ( -
- {path} -
- ))} -
); diff --git a/lib/core/docs/index.js b/lib/core/docs/index.js new file mode 100644 index 0000000000..1134a6e8d3 --- /dev/null +++ b/lib/core/docs/index.js @@ -0,0 +1,11 @@ +import React from 'react'; +import MarkdownBlock from '../markdown'; + +class Blog extends React.Component { + render() { + const {content, siteConfig} = this.props; + return {content}; + } +} + +module.exports = Blog; diff --git a/lib/core/markdown/index.js b/lib/core/markdown/index.js index 038765c7e3..c50ab500bf 100644 --- a/lib/core/markdown/index.js +++ b/lib/core/markdown/index.js @@ -10,6 +10,7 @@ class MarkdownBlock extends React.Component { const alias = { js: 'jsx' }; + const {siteConfig} = this.props; const md = new Markdown({ langPrefix: 'hljs css language-', highlight(str, lang) { @@ -99,6 +100,9 @@ class MarkdownBlock extends React.Component { render() { const Container = this.props.container; + if (!Container) { + return
{this.content()}
; + } return {this.content()}; } } diff --git a/lib/loader/blog.js b/lib/loader/blog.js index 13dbda3faf..da54415a74 100644 --- a/lib/loader/blog.js +++ b/lib/loader/blog.js @@ -36,8 +36,7 @@ async function loadBlog(siteDir) { return { path: fileToPath(file), content, - title: metadata.title, - date: metadata.date + ...metadata }; }) ); diff --git a/lib/loader/config.js b/lib/loader/config.js index 6656aab290..557edef3e2 100644 --- a/lib/loader/config.js +++ b/lib/loader/config.js @@ -2,7 +2,7 @@ const fs = require('fs-extra'); const path = require('path'); module.exports = function loadConfig(siteDir, deleteCache = true) { - const configPath = path.resolve(siteDir, 'config.js'); + const configPath = path.resolve(siteDir, 'siteConfig.js'); if (deleteCache) { delete require.cache[configPath]; } diff --git a/lib/loader/docs.js b/lib/loader/docs.js new file mode 100644 index 0000000000..a117b5deeb --- /dev/null +++ b/lib/loader/docs.js @@ -0,0 +1,47 @@ +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, '/')}.html`; +} + +function parse(fileString) { + if (!fm.test(fileString)) { + return {metadata: null, content: fileString}; + } + const {attributes: metadata, body: content} = fm(fileString); + + return {metadata, content}; +} + +async function loadDocs(siteDir) { + const blogFiles = await globby(['**/*.md'], { + cwd: siteDir + }); + + const blogDatas = await Promise.all( + blogFiles.map(async file => { + const filepath = path.resolve(siteDir, 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 = loadDocs; diff --git a/lib/loader/index.js b/lib/loader/index.js index b9cc66eda0..cd56932b5a 100644 --- a/lib/loader/index.js +++ b/lib/loader/index.js @@ -2,19 +2,33 @@ const fs = require('fs-extra'); const path = require('path'); const loadConfig = require('./config'); const loadBlog = require('./blog'); +const loadDocs = require('./docs'); const {generate} = require('../helpers'); module.exports = async function load(siteDir) { // load siteConfig const siteConfig = loadConfig(siteDir); - // extract data from all blog files - const blogDatas = await loadBlog(siteDir); - + // docs + const docsRelativeDir = siteConfig.customDocsPath || 'docs'; + const docsMetadata = await loadDocs( + path.resolve(siteDir, '..', docsRelativeDir) + ); await generate( - 'blogDatas.js', + 'docsMetadata.js', `${'/**\n * @generated\n */\n' + 'module.exports = '}${JSON.stringify( - blogDatas, + 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` @@ -32,14 +46,13 @@ module.exports = async function load(siteDir) { ? path.resolve(__dirname, '../ui') : siteConfig.uiPath; - const publicPath = siteConfig.base || '/'; + const baseUrl = siteConfig.baseUrl || '/'; return { siteConfig, - blogDatas, siteDir, outDir, uiPath, - publicPath + baseUrl }; }; diff --git a/lib/webpack/base.js b/lib/webpack/base.js index 29bffe0567..b84a05d719 100644 --- a/lib/webpack/base.js +++ b/lib/webpack/base.js @@ -2,7 +2,7 @@ const Config = require('webpack-chain'); const path = require('path'); module.exports = function createBaseConfig(props) { - const {outDir, uiPath, siteDir, publicPath} = props; + const {outDir, uiPath, siteDir, baseUrl} = props; const config = new Config(); const isProd = process.env.NODE_ENV === 'production'; @@ -13,7 +13,7 @@ module.exports = function createBaseConfig(props) { .filename( isProd ? 'static/js/[name].[chunkhash].js' : 'static/js/[name].js' ) - .publicPath(isProd ? publicPath : '/'); + .publicPath(isProd ? baseUrl : '/'); config.resolve .set('symlinks', true) diff --git a/package.json b/package.json index 4218cdff92..374f2436dd 100644 --- a/package.json +++ b/package.json @@ -51,15 +51,18 @@ "front-matter": "^2.3.0", "fs-extra": "^7.0.0", "globby": "^8.0.1", + "highlight.js": "^9.12.0", "html-webpack-plugin": "^3.2.0", "koa-connect": "^2.0.1", "koa-mount": "^3.0.0", "koa-range": "^0.3.0", "koa-static": "^5.0.0", "portfinder": "^1.0.13", + "prismjs": "^1.15.0", "react": "^16.4.1", "react-dom": "^16.4.1", "react-router-dom": "^4.3.1", + "remarkable": "^1.7.1", "semver": "^5.5.0", "webpack": "^4.16.3", "webpack-chain": "^4.8.0", diff --git a/yarn.lock b/yarn.lock index 88553e302e..31940932f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -379,6 +379,13 @@ argparse@^1.0.7: dependencies: sprintf-js "~1.0.2" +argparse@~0.1.15: + version "0.1.16" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-0.1.16.tgz#cfd01e0fbba3d6caed049fbd758d40f65196f57c" + dependencies: + underscore "~1.7.0" + underscore.string "~2.4.0" + aria-query@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/aria-query/-/aria-query-3.0.0.tgz#65b3fcc1ca1155a8c9ae64d6eee297f15d5133cc" @@ -517,6 +524,10 @@ atob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" +autolinker@~0.15.0: + version "0.15.3" + resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-0.15.3.tgz#342417d8f2f3461b14cf09088d5edf8791dc9832" + aws-sign2@~0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" @@ -1492,6 +1503,14 @@ cli-width@^2.0.0: version "2.2.0" resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639" +clipboard@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-2.0.1.tgz#a12481e1c13d8a50f5f036b0560fe5d16d74e46a" + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + clipboardy@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/clipboardy/-/clipboardy-1.2.3.tgz#0526361bf78724c1f20be248d428e365433c07ef" @@ -1895,6 +1914,10 @@ delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" +delegate@^3.1.2: + version "3.2.0" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.2.0.tgz#b66b71c3158522e8ab5744f720d8ca0c2af59166" + delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" @@ -2846,6 +2869,12 @@ globby@^8.0.1: pify "^3.0.0" slash "^1.0.0" +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + dependencies: + delegate "^3.1.2" + got@^6.7.1: version "6.7.1" resolved "https://registry.yarnpkg.com/got/-/got-6.7.1.tgz#240cd05785a9a18e561dc1b44b41c763ef1e8db0" @@ -2970,6 +2999,10 @@ he@1.1.x: version "1.1.1" resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" +highlight.js@^9.12.0: + version "9.12.0" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e" + history@^4.7.2: version "4.7.2" resolved "https://registry.yarnpkg.com/history/-/history-4.7.2.tgz#22b5c7f31633c5b8021c7f4a8a954ac139ee8d5b" @@ -5132,6 +5165,12 @@ pretty-time@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/pretty-time/-/pretty-time-1.1.0.tgz#ffb7429afabb8535c346a34e41873adf3d74dd0e" +prismjs@^1.15.0: + version "1.15.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.15.0.tgz#8801d332e472091ba8def94976c8877ad60398d9" + optionalDependencies: + clipboard "^2.0.0" + private@^0.1.6, private@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff" @@ -5505,6 +5544,13 @@ relateurl@0.2.x: version "0.2.7" resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" +remarkable@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-1.7.1.tgz#aaca4972100b66a642a63a1021ca4bac1be3bff6" + dependencies: + argparse "~0.1.15" + autolinker "~0.15.0" + remove-array-items@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/remove-array-items/-/remove-array-items-1.0.0.tgz#07bf42cb332f4cf6e85ead83b5e4e896d2326b21" @@ -5737,6 +5783,10 @@ schema-utils@^0.4.4, schema-utils@^0.4.5: ajv "^6.1.0" ajv-keywords "^3.1.0" +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + semver-diff@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36" @@ -6211,6 +6261,10 @@ timers-browserify@^2.0.4: dependencies: setimmediate "^1.0.4" +tiny-emitter@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.2.tgz#82d27468aca5ade8e5fd1e6d22b57dd43ebdfb7c" + tmp@^0.0.33: version "0.0.33" resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" @@ -6361,6 +6415,14 @@ uglifyjs-webpack-plugin@^1.2.4: webpack-sources "^1.1.0" worker-farm "^1.5.2" +underscore.string@~2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b" + +underscore@~1.7.0: + version "1.7.0" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.7.0.tgz#6bbaf0877500d36be34ecaa584e0db9fef035209" + union-value@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.0.tgz#5c71c34cb5bad5dcebe3ea0cd08207ba5aa1aea4"