Skip to content

Commit 624e733

Browse files
committed
feat(doc): 添加 PC 文档框架
1 parent 0d80914 commit 624e733

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+3596
-1
lines changed

Diff for: .babelrc

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"presets": [
3+
[
4+
"@babel/preset-env",
5+
{
6+
"spec": true,
7+
"modules": false,
8+
"targets": {
9+
"browsers": ["ie >= 9", "Chrome >= 21", "Firefox >= 1", "Edge >= 13", "last 3 versions"]
10+
},
11+
"loose": false,
12+
"forceAllTransforms" : true,
13+
"useBuiltIns": "entry"
14+
15+
}
16+
]
17+
],
18+
"plugins": [
19+
"syntax-dynamic-import",
20+
"@babel/plugin-proposal-class-properties",
21+
[
22+
"@babel/plugin-transform-react-jsx",
23+
{
24+
"pragma": "Nerv.createElement"
25+
}
26+
]
27+
]
28+
}

Diff for: .eslintignore

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ coverage/
66
.nyc_output/
77
git_stats/
88
yarn-offline/
9+
docs/

Diff for: .stylelintignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
docs/
2+
.jsx

Diff for: build/addImportLoader.js

+179
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
const mdContainer = require('markdown-it-container')
2+
const frontMatter = require('front-matter')
3+
const highlight = require('highlight.js')
4+
5+
let md = require('markdown-it')
6+
7+
const options = {
8+
className: 'wrap'
9+
}
10+
11+
md = md({
12+
html: true, // Enable HTML tags in source
13+
xhtmlOut: true,
14+
typographer: false,
15+
linkify: false
16+
})
17+
.enable(['smartquotes'])
18+
.set({
19+
highlight (content, languageHint) {
20+
let highlightedContent
21+
22+
highlight.configure({
23+
useBR: true,
24+
tabReplace: ' '
25+
})
26+
27+
if (languageHint && highlight.getLanguage(languageHint)) {
28+
try {
29+
highlightedContent = highlight.highlight(languageHint, content).value
30+
} catch (err) {
31+
console.log(err)
32+
}
33+
}
34+
35+
if (!highlightedContent) {
36+
try {
37+
highlightedContent = highlight.highlightAuto(content).value
38+
} catch (err) {
39+
console.log(err)
40+
}
41+
}
42+
43+
// 把代码中的{}转
44+
highlightedContent = highlightedContent.replace(/[{}]/g, match => `{'${match}'}`)
45+
46+
// 加上 hljs
47+
highlightedContent = highlightedContent
48+
.replace('<code class="', '<code class="hljs ')
49+
.replace('<code>', '<code class="hljs">')
50+
51+
return highlight.fixMarkup(highlightedContent)
52+
}
53+
})
54+
55+
const formatModule = (imports, js, jsx, state, method) => {
56+
const moduleText = `
57+
${imports}
58+
59+
${js}
60+
61+
class MarkdownItReactComponent extends Nerv.Component {
62+
constructor(props){
63+
super(props);
64+
this.state = ${state || '{}'};
65+
Object.assign(this,props.methods)
66+
}
67+
handleToggleCode(flag){
68+
const state = {};
69+
state['showCode' + flag] = !this.state['showCode' + flag];
70+
this.setState(state);
71+
}
72+
handleCopyCode (code) {
73+
copy(code)
74+
}
75+
${method || ''}
76+
render(){
77+
78+
return (
79+
<div className="${options.className}">
80+
${jsx}
81+
</div>
82+
);
83+
}
84+
};
85+
86+
export default MarkdownItReactComponent;`
87+
88+
return moduleText
89+
}
90+
91+
const formatOpening = (code, description, flag) => {
92+
return ` <div className="at-component__container">
93+
<div className="at-component__sample">
94+
${code}
95+
</div>
96+
<div className="${options.className}-demo-meta" >
97+
<div className="at-component__code" style={{display: this.state.showCode${flag}? '' : 'none' }}>
98+
`
99+
}
100+
101+
const formatClosing = flag => {
102+
return `</div>
103+
<div className="at-component__code-toggle" onClick={this.handleToggleCode.bind(this, ${flag})}>
104+
{ this.state.showCode${flag} ? '隐藏代码':'显示代码'}
105+
</div>
106+
</div>
107+
</div>`
108+
}
109+
110+
module.exports = function (source) {
111+
this.cacheable()
112+
// init options
113+
Object.assign(options, this.options.markdownItReact ? this.options.markdownItReact() : {})
114+
115+
const {
116+
body,
117+
attributes: { imports: importMap }
118+
} = frontMatter(source)
119+
120+
const imports = `import * as Nerv from 'nervjs'; import copy from 'copy-to-clipboard';${importMap}`
121+
122+
const moduleJS = []
123+
let state = ''
124+
// 放在这里应该没有问题, 反正是顺序执行的
125+
let flag = ''
126+
127+
md.use(mdContainer, 'demo', {
128+
validate: params => params.trim().match(/^demo\s*(.*)$/),
129+
render: (tokens, idx) => {
130+
// container 从开头到结尾把之间的token跑一遍,其中idx定位到具体的位置
131+
132+
// 获取描述
133+
const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/)
134+
135+
// 有此标记代表 ::: 开始
136+
if (tokens[idx].nesting === 1) {
137+
flag = idx
138+
139+
let jsx = ''
140+
// let state = null
141+
// let method = ''
142+
let i = 1
143+
144+
// 从 ::: 下一个token开始
145+
let token = tokens[idx + i]
146+
147+
// 如果没有到结尾
148+
while (token.markup !== ':::') {
149+
// 只认```,其他忽略
150+
if (token.markup === '```') {
151+
if (token.info === 'js') {
152+
// 插入到import后,component前
153+
moduleJS.push(token.content)
154+
} else if (token.info === 'jsx' || token.info === 'html') {
155+
// 插入render内
156+
jsx = token.content
157+
} else if (token.info === 'state') {
158+
// console.log(typeof )
159+
state = token.content.replace(/\\[a-z]/g, ' ').replace(/'/g, `"`)
160+
}
161+
}
162+
i++
163+
token = tokens[idx + i]
164+
}
165+
// 描述也执行md
166+
return formatOpening(jsx, md.render(m[1]), flag)
167+
}
168+
return formatClosing(flag)
169+
}
170+
})
171+
172+
// md 处理过后的字符串含有 class 和 style ,需要再次处理给到react
173+
const content = md
174+
.render(body)
175+
.replace(/<hr>/g, '<hr />')
176+
.replace(/<br>/g, '<br />')
177+
.replace(/class=/g, 'className=')
178+
return formatModule(imports, moduleJS.join('\n'), content, state)
179+
}

Diff for: build/conf.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
output: 'siteoutput'
3+
}

Diff for: build/dev-server.js

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
const path = require('path')
2+
const chalk = require('chalk')
3+
const webpack = require('webpack')
4+
const WebpackDevServer = require('webpack-dev-server')
5+
// const HtmlWebpackPlugin = require('html-webpack-plugin')
6+
const webpackMerge = require('webpack-merge')
7+
const ora = require('ora')
8+
9+
const { getProjectRoot, prepareUrls, formatTime } = require('./util')
10+
const conf = require('./conf')
11+
const webpackBaseConf = require('./webpack.base.config')
12+
const webpackDevConf = require('./webpack.dev.config')
13+
const formatWebpackMessage = require('./format_webpack_message')
14+
const open = require('./open')
15+
16+
const serveSpinner = ora('Starting build...').start()
17+
18+
const projectRoot = getProjectRoot()
19+
const host = '0.0.0.0'
20+
const port = 8002
21+
const protocol = 'http'
22+
const urls = prepareUrls(protocol, host, port)
23+
const webpackConf = webpackMerge(webpackBaseConf, webpackDevConf)
24+
for (const key in webpackConf.entry) {
25+
const entryItem = webpackConf.entry[key]
26+
if (Array.isArray(entryItem)) {
27+
entryItem.unshift(require.resolve('webpack/hot/dev-server'))
28+
entryItem.unshift(`${require.resolve('webpack-dev-server/client')}?/`)
29+
} else {
30+
webpackConf.entry[key] = [
31+
`${require.resolve('webpack-dev-server/client')}?/`,
32+
require.resolve('webpack/hot/dev-server'),
33+
entryItem
34+
]
35+
}
36+
}
37+
const compiler = webpack(webpackConf)
38+
const webpackDevServerConf = require('./devServer.conf')({
39+
publicPath: '/',
40+
contentBase: path.join(projectRoot, conf.output),
41+
protocol,
42+
host,
43+
publicUrl: urls.lanUrlForConfig
44+
})
45+
46+
const server = new WebpackDevServer(compiler, webpackDevServerConf)
47+
server.listen(port, host, err => {
48+
if (err) {
49+
return console.log(err)
50+
}
51+
})
52+
let isFirstCompile = true
53+
compiler.plugin('invalid', filepath => {
54+
console.log(chalk.grey(`[${formatTime()}]Modified: ${filepath}`))
55+
serveSpinner.text = 'Compiling...🤡~'
56+
serveSpinner.render()
57+
})
58+
compiler.plugin('done', stats => {
59+
const { errors, warnings } = formatWebpackMessage(stats.toJson({}, true))
60+
const isSuccess = !errors.length && !warnings.length
61+
if (isSuccess) {
62+
serveSpinner.succeed(chalk.green('Compile successfully!\n'))
63+
}
64+
if (errors.length) {
65+
errors.splice(1)
66+
serveSpinner.fail(chalk.red('Compile failed!\n'))
67+
console.log(errors.join('\n\n'))
68+
console.log()
69+
}
70+
if (isFirstCompile) {
71+
console.log(chalk.cyan(`> Listening at ${urls.lanUrlForTerminal}`))
72+
console.log(chalk.cyan(`> Listening at ${urls.localUrlForBrowser}`))
73+
console.log()
74+
open(urls.localUrlForBrowser)
75+
isFirstCompile = false
76+
}
77+
})

Diff for: build/devServer.conf.js

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
module.exports = function ({ publicPath, contentBase, protocol, host, publicUrl }) {
2+
return {
3+
disableHostCheck: process.env.DANGEROUSLY_DISABLE_HOST_CHECK === 'true',
4+
compress: true,
5+
contentBase,
6+
watchContentBase: true,
7+
hot: true,
8+
inline: true,
9+
quiet: true,
10+
publicPath,
11+
// stats: "errors-only",
12+
watchOptions: {
13+
ignored: /node_modules/
14+
},
15+
https: protocol === 'https',
16+
host,
17+
// overlay: true,
18+
historyApiFallback: {
19+
disableDotRule: true
20+
},
21+
public: publicUrl
22+
}
23+
}

Diff for: build/format_webpack_message.js

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
const chalk = require('chalk')
2+
3+
const syntaxErrorLabel = 'Syntax error:'
4+
5+
function isLikelyASyntaxError (message) {
6+
return message.indexOf(syntaxErrorLabel) >= 0
7+
}
8+
9+
function formatMessage (message) {
10+
let lines = message.split('\n')
11+
if (lines.length > 2 && lines[1] === '') {
12+
lines.splice(1, 1)
13+
}
14+
if (lines[0].lastIndexOf('!') >= 0) {
15+
lines[0] = lines[0].substr(lines[0].lastIndexOf('!') + 1)
16+
}
17+
lines = lines.filter(line => line.indexOf(' @ ') !== 0)
18+
if (!lines[0] || !lines[1]) {
19+
return lines.join('\n')
20+
}
21+
if (lines[1].indexOf('Module not found: ') === 0) {
22+
lines = [
23+
lines[0],
24+
lines[1]
25+
.replace("Cannot resolve 'file' or 'directory' ", '')
26+
.replace('Cannot resolve module ', '')
27+
.replace('Error: ', '')
28+
.replace('[CaseSensitivePathsPlugin] ', '')
29+
]
30+
} else if (lines[1].indexOf('Module build failed: ') === 0) {
31+
lines[1] = lines[1].replace(
32+
'Module build failed: SyntaxError:',
33+
syntaxErrorLabel
34+
)
35+
}
36+
37+
const exportError = /\s*(.+?)\s*(")?export '(.+?)' was not found in '(.+?)'/
38+
if (lines[1].match(exportError)) {
39+
lines[1] = lines[1].replace(
40+
exportError,
41+
"$1 '$4' does not contain an export named '$3'."
42+
)
43+
}
44+
lines[0] = chalk.inverse(lines[0])
45+
message = lines.join('\n')
46+
47+
message = message.replace(/^\s*at\s((?!webpack:).)*:\d+:\d+[\s)]*(\n|$)/gm, '')
48+
return message.trim()
49+
}
50+
51+
module.exports = function formatWebpackMessage (message) {
52+
const errors = message.errors.map(item => formatMessage(item))
53+
const warnings = message.warnings.map(item => formatMessage(item))
54+
55+
const result = {
56+
errors,
57+
warnings
58+
}
59+
if (result.errors.some(isLikelyASyntaxError)) {
60+
result.errors = result.errors.filter(isLikelyASyntaxError)
61+
}
62+
return result
63+
}

0 commit comments

Comments
 (0)