├── src ├── web │ ├── rdoc.tree.data.json │ ├── index.js │ └── Router.js ├── commands │ ├── clean.js │ └── initProject.js ├── build.js ├── publish.js ├── conf │ ├── webpack.config.server.js │ ├── webpack.config.js │ ├── path.js │ ├── webpack.config.dev.js │ └── webpack.config.prod.js ├── utils │ └── initCatch.js └── server.js ├── rdoc.png ├── theme └── default │ ├── lib │ └── markdown │ │ ├── style │ │ ├── diff.less │ │ ├── xml.less │ │ ├── swift.less │ │ ├── css.less │ │ ├── javascript.less │ │ ├── index.less │ │ └── default.less │ │ ├── Link.less │ │ ├── InlineCode.less │ │ ├── Link.js │ │ ├── InlineCode.js │ │ └── index.js │ ├── favicon.ico │ ├── component │ ├── Loading │ │ ├── index.less │ │ └── index.js │ ├── Footer │ │ ├── index.less │ │ └── index.js │ ├── NoMatch │ │ ├── index.js │ │ └── index.less │ └── Header │ │ ├── index.less │ │ └── index.js │ ├── routes │ └── Pages │ │ └── index.js │ ├── layout │ ├── IndexLayout.less │ ├── BasicLayout.less │ ├── IndexLayout.js │ └── BasicLayout.js │ ├── index.html │ ├── index.less │ ├── rdoc.logo.svg │ └── index.js ├── templates └── default │ ├── introduce │ ├── api │ │ ├── README.md │ │ ├── markdown-config.md │ │ ├── commands.md │ │ ├── conf.md │ │ └── theme-api.md │ ├── guides │ │ ├── README.md │ │ ├── add-blog.md │ │ ├── website.md │ │ ├── menu-sort.md │ │ ├── add-index.md │ │ ├── link.md │ │ ├── insert-img.md │ │ ├── html.md │ │ ├── custom-menu.md │ │ └── theme.md │ ├── getting-started │ │ ├── README.md │ │ ├── install.md │ │ ├── site-preparation.md │ │ ├── publish.md │ │ └── site-creation.md │ ├── README.md │ ├── assets │ │ └── react-logo.svg │ ├── precautions.md │ └── init-project.md │ ├── github │ └── README.md │ ├── about │ └── README.md │ ├── _.gitignore │ ├── _.editorconfig │ ├── faq │ └── README.md │ ├── _package.json │ └── home │ └── README.md ├── .npmignore ├── .gitignore ├── .editorconfig ├── .github └── FUNDING.yml ├── .babelrc.js ├── .eslintrc.js ├── .bin └── rdoc.js ├── package.json ├── README_zh.md └── README.md /src/web/rdoc.tree.data.json: -------------------------------------------------------------------------------- 1 | [] 2 | -------------------------------------------------------------------------------- /rdoc.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaywcjlove/rdoc/HEAD/rdoc.png -------------------------------------------------------------------------------- /theme/default/lib/markdown/style/diff.less: -------------------------------------------------------------------------------- 1 | .language-diff { 2 | 3 | } -------------------------------------------------------------------------------- /theme/default/lib/markdown/style/xml.less: -------------------------------------------------------------------------------- 1 | .language-html, .xml{ 2 | 3 | } 4 | -------------------------------------------------------------------------------- /templates/default/introduce/api/README.md: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /templates/default/introduce/guides/README.md: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /templates/default/introduce/getting-started/README.md: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /theme/default/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jaywcjlove/rdoc/HEAD/theme/default/favicon.ico -------------------------------------------------------------------------------- /templates/default/github/README.md: -------------------------------------------------------------------------------- 1 | 5 | -------------------------------------------------------------------------------- /templates/default/introduce/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .cache 2 | .gitignore 3 | .editorconfig 4 | .rdoc-dist 5 | node_modules 6 | package-lock.json 7 | dist 8 | rdoc.png 9 | -------------------------------------------------------------------------------- /theme/default/component/Loading/index.less: -------------------------------------------------------------------------------- 1 | .loading { 2 | text-align: center; 3 | min-height: 450px; 4 | padding: 30px 0; 5 | } 6 | -------------------------------------------------------------------------------- /templates/default/about/README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 这是一个文档生成工具,用于生成文档网站或简单的博客网站,你可以放到项目中依赖,也可以单独使用,更轻松的制作一个网站或者文档网站。 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .rdoc-dist 3 | package-lock.json 4 | .cache 5 | .DS_Store 6 | 7 | *.bak 8 | *.tem 9 | *.log 10 | *.temp 11 | #.swp 12 | *.*~ 13 | ~*.* 14 | -------------------------------------------------------------------------------- /theme/default/lib/markdown/Link.less: -------------------------------------------------------------------------------- 1 | .frame { 2 | width: 100%; 3 | min-height: 400px; 4 | border: 1px solid #e9e9e9; 5 | border-radius: 3px; 6 | background: #fff; 7 | } 8 | -------------------------------------------------------------------------------- /templates/default/_.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | package-lock.json 3 | .DS_Store 4 | .cache 5 | .rdoc-dist 6 | 7 | *.bak 8 | *.log 9 | *.tem 10 | *.temp 11 | #.swp 12 | *.*~ 13 | ~*.* 14 | -------------------------------------------------------------------------------- /theme/default/routes/Pages/index.js: -------------------------------------------------------------------------------- 1 | import Markdown from '../../lib/markdown'; 2 | 3 | export default class Pages extends Markdown { 4 | constructor(props) { 5 | super(props); 6 | this.page = props.page; 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /theme/default/component/Loading/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styles from './index.less'; 3 | 4 | const Loading = () => { 5 | return ( 6 |
7 | 正在加载中.... 8 |
9 | ); 10 | }; 11 | 12 | export default Loading; 13 | -------------------------------------------------------------------------------- /theme/default/layout/IndexLayout.less: -------------------------------------------------------------------------------- 1 | .header { 2 | background-color: transparent; 3 | box-shadow: 0 0 0 #fff; 4 | border-bottom: 0; 5 | background-color: rgba(255, 255, 255, 0.9); 6 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); 7 | } 8 | .wapper { 9 | min-height: 500px; 10 | padding: 57px 0 0 0; 11 | } 12 | -------------------------------------------------------------------------------- /theme/default/lib/markdown/style/swift.less: -------------------------------------------------------------------------------- 1 | .language-swift { 2 | .keyword, .selector-tag, .subst { 3 | color: #C600AA; 4 | font-weight: normal; 5 | } 6 | .meta { 7 | color: #C526D0; 8 | font-weight: normal; 9 | } 10 | .type, .class .title { 11 | color: #7C10B2; 12 | font-weight: normal; 13 | } 14 | } -------------------------------------------------------------------------------- /theme/default/component/Footer/index.less: -------------------------------------------------------------------------------- 1 | .footer { 2 | font-size: 14px; 3 | text-align: center; 4 | border-top: 1px solid #e9e9e9; 5 | margin-top: 50px; 6 | padding: 20px 0 50px 0; 7 | clear: both; 8 | color: #999; 9 | a { 10 | color: #758AC5; 11 | &:hover { 12 | color: #0800ff; 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/web/index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-named-as-default-member */ 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import '@babel/polyfill'; 5 | // eslint-disable-next-line import/no-named-as-default 6 | import RouterRoot from './Router'; 7 | 8 | ReactDOM.render( 9 | , 10 | document.getElementById('root') 11 | ); 12 | 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.less] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [Makefile] 20 | indent_style = tab 21 | -------------------------------------------------------------------------------- /templates/default/_.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | 15 | [*.less] 16 | indent_style = space 17 | indent_size = 2 18 | 19 | [Makefile] 20 | indent_style = tab 21 | -------------------------------------------------------------------------------- /src/commands/clean.js: -------------------------------------------------------------------------------- 1 | const FS = require('fs-extra'); 2 | const paths = require('../conf/path'); 3 | 4 | module.exports = function (params) { 5 | if (params.build && FS.pathExistsSync(paths.appBuildDist)) { 6 | // 清空目录 7 | FS.emptyDirSync(paths.appBuildDist); 8 | } 9 | if (params.clean && FS.pathExistsSync(paths.catchDirPath)) { 10 | // 清空目录 11 | FS.emptyDirSync(paths.catchDirPath); 12 | } 13 | }; 14 | -------------------------------------------------------------------------------- /templates/default/faq/README.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 这里可以问一些常见问题。 7 | 8 | 1. 是否支持 Markdown 中写代码? 9 | 10 | > 支持在 Markdown 中写HTML、CSS。 11 | 12 | 2. 文档是否支持目录层级? 13 | 14 | > 支持菜单无线层级,在文件夹中建立文件夹,相对应建立 `README.md` 15 | 16 | 3. 新增文件不能热加载,监听文件变化? 17 | 18 | > 新增一个 `Markdown` 文件是支持热加载的,需要如下步骤: 19 | > - 添加完成之后必须 `Markdown` 文件不能为空。 20 | > - 如果只是添加注释配置或者空格,一样视为空。 21 | > - 在其它已加载的 `Markdown` 文件中保存一下。 22 | -------------------------------------------------------------------------------- /theme/default/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <%= htmlWebpackPlugin.options.title %> 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: jaywcjlove 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: npm/rdoc 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | custom: https://jaywcjlove.github.io/sponsor.html 10 | -------------------------------------------------------------------------------- /templates/default/introduce/assets/react-logo.svg: -------------------------------------------------------------------------------- 1 | 2 | React Logo 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /templates/default/introduce/precautions.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ⚠️ 在使用文档生成工具是,应注意一些事项,避免生成文档过程出现错误。 7 | 8 | 1. 文件与文件夹不能重名。 9 | 2. 顶部菜单通过 `sort` 排序是无效的。 10 | 5. HTML 中写 ` 53 | 54 | 55 | ## HTML Demo 预览 56 | 57 | 需要在代码块前后加上一段 ` ` 和 `` 注释即可,代码如下: 58 | 59 | ``` 60 | 61 | \```html 62 |
63 | Test Preview HTML Example. 64 |
65 | 68 | \``` 69 | 70 | ``` 71 | 72 | 下面是效果 73 | 74 | 75 | ```html 76 |
77 | Test Preview HTML Example. 78 |
79 | 82 | ``` 83 | 84 | 85 | 目前只预览 `HTML`, 下面为 `LESS` 展示 86 | 87 | 88 | ```less 89 | .wapper { 90 | &::after { 91 | content: ''; 92 | display: block; 93 | clear: both; 94 | } 95 | } 96 | 97 | .wapperContent { 98 | padding: 15px 0 0 0; 99 | max-width: 1200px; 100 | margin: 0px auto 0; 101 | } 102 | ``` 103 | 104 | -------------------------------------------------------------------------------- /theme/default/rdoc.logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /templates/default/introduce/guides/custom-menu.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ## 主菜单定制 7 | 8 | 主菜单的定制,是通过 `建立` 目录来定制的,默认菜单名字是根据目录文件夹名字来显示,下面实例定义了主菜单有三个菜单,顺序分别为 `tutorial`、`doc`、`component` 9 | 10 | ```shell 11 | $ rdoc -d tutorial,doc 12 | ``` 13 | 14 | 可以自定义菜单名字,通过在文件夹的跟目录建立 `README.md` 添加配置来设置菜单的名字。 15 | 16 | ```markdown 17 | 20 | ``` 21 | 22 | ⚠️ 通过配置菜单对应根目录下的 `README.md` 来改变 `菜单顺序` 和 `是否显示`,[配置参考](#/introduce/api/markdown-config)。 23 | 24 | > sort 菜单顺序 25 | > visible 菜单是否显示 `true` 不显示 26 | 27 | ## Github跳转 28 | 29 | 新建一个目录 `github`,命令配置 `rdoc -d tutorial,doc,github` 将在主菜单上显示,在 `github` 目录下新建 `READEME.md` 文件,添加 Markdown 配置如下: 30 | 31 | > ⚠️ 注意: github 配置项,会增加 `github` 图标 32 | > 如果不想显示`图标`,就将 `github` 指定 `url` 配置。 33 | 34 | ```markdown 35 | 40 | ``` 41 | 42 | ## 子菜单定制 43 | 44 | 在某个菜单下面定制二级菜单,默认情况,只需要在该目录创建多个 `.md` 文件,如下目录结构,有四个子菜单`api`、`getting-started`、`guides`、`precautions`。 45 | 46 | > ⚠️ 注意: 文件夹不能跟文件重名 47 | 48 | ```shell 49 | └── introduce 50 |    ├── README.md 51 |    ├── api 52 |    │   ├── README.md 53 |    │   └── menu-config.md 54 |    ├── getting-started 55 |    │   ├── README.md 56 |    │   └── site-preparation.md 57 |    ├── guides 58 |    │   ├── README.md 59 |    │   └── menu-sort.md 60 |    └── precautions.md 61 | ``` 62 | 63 | ## 子菜单菜层级 64 | 65 | 以相同的方式在该目录下面创建目录,并且创建 `.md` 文件,再添加相应的配置即可,如下目录结构,二级菜单将有三层。 66 | 67 | ```shell 68 | └── introduce 69 |    ├── README.md 70 |    ├── api 71 |    │   ├── README.md 72 |    │ ├── getting-started 73 | │   │   ├── README.md 74 | │   │   └── site-preparation.md 75 |    │   └── menu-config.md 76 |    └── precautions.md 77 | ``` 78 | 79 | ## 菜单分类 80 | 81 | 子菜单分类是根据目录结构来分类的,假设你新建如下目录结构,配置的命令指向目录 `introduce`,那么你根目录下面的 `README.md` 里面可以配置一级导航的信息内容,二级目录文件夹分别为导航菜单的分类名称。 82 | 83 | 在 `introduce` 目录下面的,每个目录下,面再新建 `README.md` 来配置分类的各种信息,如此循环下去,可以新建一个树形菜单。 84 | 85 | ```shell 86 | └── introduce 87 |    ├── README.md 88 |    ├── api 89 |    │   ├── README.md 90 |    │   └── menu-config.md 91 |    ├── getting-started 92 |    │   ├── README.md 93 |    │   └── site-preparation.md 94 |    ├── guides 95 |    │   ├── README.md 96 |    │   └── menu-sort.md 97 |    └── precautions.md 98 | ``` 99 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | const eslintrc = { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "env": { 5 | "browser": true, 6 | "node": true, 7 | "es6": true, 8 | "mocha": true, 9 | "jest": true, 10 | "jasmine": true 11 | }, 12 | "plugins": [ 13 | "react", 14 | "import" 15 | ], 16 | "parserOptions": { 17 | parser: 'babel-eslint', 18 | }, 19 | "rules": { 20 | "linebreak-style": 0, 21 | "func-names": 0, 22 | "sort-imports": 0, 23 | "arrow-body-style": 0, 24 | "prefer-destructuring": 0, 25 | "max-len": 0, 26 | "consistent-return": 0, 27 | "comma-dangle": [ 28 | "error", 29 | "always-multiline" 30 | ], 31 | "function-paren-newline": 0, 32 | "class-methods-use-this": 0, 33 | "react/sort-comp": 0, 34 | "react/prop-types": 0, 35 | "react/jsx-first-prop-new-line": 0, 36 | "react/require-extension": 0, 37 | "react/jsx-filename-extension": [ 38 | 1, 39 | { 40 | "extensions": [ 41 | ".js", 42 | ".jsx" 43 | ] 44 | } 45 | ], 46 | "import/extensions": 0, 47 | "import/no-unresolved": 0, 48 | "import/no-extraneous-dependencies": 0, 49 | "import/prefer-default-export": 0, 50 | "jsx-a11y/no-static-element-interactions": 0, 51 | "jsx-a11y/anchor-has-content": 0, 52 | "jsx-a11y/click-events-have-key-events": 0, 53 | "jsx-a11y/anchor-is-valid": 0, 54 | "jsx-a11y/label-has-for": 0, 55 | "jsx-a11y/no-noninteractive-element-interactions": 0, 56 | "jsx-a11y/mouse-events-have-key-events": 0, 57 | "react/no-danger": 0, 58 | "react/jsx-no-bind": 0, 59 | "react/forbid-prop-types": 0, 60 | "react/require-default-props": 0, 61 | "react/no-did-mount-set-state": 0, 62 | "react/no-array-index-key": 0, 63 | "react/no-find-dom-node": 0, 64 | "react/no-unused-state": 0, 65 | "react/no-unused-prop-types": 0, 66 | "react/default-props-match-prop-types": 0, 67 | "react/jsx-curly-spacing": 0, 68 | "react/no-render-return-value": 0, 69 | "object-curly-newline": 0, 70 | "no-param-reassign": 0, 71 | "no-return-assign": 0, 72 | "no-redeclare": 0, 73 | "no-restricted-globals": 0, 74 | "no-restricted-syntax": 0, 75 | "no-underscore-dangle": 0, 76 | "no-unused-expressions": 0 77 | } 78 | } 79 | 80 | if (process.env.NODE_ENV === 'development') { 81 | Object.assign(eslintrc.rules, 82 | { 83 | 'no-console': 0, 84 | 'no-unused-vars': 0, 85 | }); 86 | } 87 | 88 | module.exports = eslintrc 89 | -------------------------------------------------------------------------------- /.bin/rdoc.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | const FS = require('fs-extra'); 3 | const PATH = require('path'); 4 | const program = require('commander'); 5 | const color = require('colors-cli/toxic'); 6 | const initProject = require('../src/commands/initProject'); 7 | const clean = require('../src/commands/clean'); 8 | const initCatch = require('../src/utils/initCatch'); 9 | const Servers = require('../src/server'); 10 | const Build = require('../src/build'); 11 | const Publish = require('../src/publish'); 12 | const paths = require('../src/conf/path'); 13 | const pkg = require('../package.json') 14 | 15 | program 16 | .version(pkg.version, '-v, --version') 17 | .description('Fast static site generator for React.') 18 | .option('-i, init [path]', 'Create an empty website or reinitialize an existing one.') 19 | .option('-d, --doc ', 'Other documents generated.') 20 | .option('-o, --output ', 'Writes the compiled file to the disk directory.', '.rdoc-dist') 21 | .option('-p, --port [number]', 'The port.', 5858) 22 | .option('--host [host]', 'The host.', '0.0.0.0') 23 | .option('-b, --branch ', 'Name of the branch you are pushing to.', 'gh-pages') 24 | .option('--publish [url]', 'Other documents generated.') 25 | .option('--build', 'Creating an optimized production build.') 26 | .option('--clean', 'Delete the .cache folder.') 27 | .on('--help', function () { 28 | console.log('\n Examples:'); 29 | console.log(); 30 | console.log(' $ rdoc init'); 31 | console.log(' $ rdoc init doc-example'); 32 | console.log(' $ rdoc -d doc/mm'); 33 | console.log(' $ rdoc -d tutorial,doc'); 34 | console.log(' $ rdoc -d tutorial,doc --clean --build'); 35 | console.log(' $ rdoc -p 2323 -d doc --clean'); 36 | console.log(' $ rdoc -h 0.0.0.0 -d doc --clean'); 37 | console.log(' $ rdoc --publish https://.git --branch master'); 38 | console.log(); 39 | }) 40 | .parse(process.argv); 41 | // rdoc 工具根目录 42 | // program.rdocPath = PATH.join(__dirname, '../'); 43 | // 所有 Markdown 目录 44 | program.markdownPaths = []; 45 | // 网站根目录 46 | program.projectPath = process.cwd(); 47 | // 编译输出目录 48 | program.output = PATH.join(program.projectPath, program.output); 49 | 50 | // 网站根目录,指定的所有 Markdown 的目录 51 | if (program.doc) { 52 | program.doc.split(',').forEach((itemPath) => program.markdownPaths.push(PATH.join(program.projectPath, itemPath))); 53 | } 54 | 55 | if (program.clean) clean(program); 56 | if (program.init) return initProject(program); 57 | 58 | // 将生成的代码,push到指定仓库,已经分支。 59 | if (program.publish) { 60 | return Publish(program) 61 | } 62 | 63 | // 没有指定,文档目录 64 | if (program.markdownPaths.length === 0) return console.log(`Please specify the directory with the parameters "-d".`.red) 65 | 66 | let isExists = true; 67 | // 判断指定文件夹是否存 68 | program.markdownPaths.forEach((item) => { 69 | if (!FS.existsSync(item)) { 70 | console.log(`Error: Directory ${item.yellow} does not exist`.red) 71 | isExists = false; 72 | } 73 | }); 74 | 75 | if (isExists) { 76 | FS.ensureDirSync(paths.catchDirPath); 77 | initCatch(program, () => { 78 | if (program.build) { 79 | Build(program); 80 | } else { 81 | Servers(program); 82 | } 83 | }) 84 | } 85 | -------------------------------------------------------------------------------- /theme/default/lib/markdown/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import classNames from 'classnames'; 4 | import ReactMarkdown from 'react-markdown'; 5 | import hljs from 'highlight.js'; 6 | import styles from './style/index.less'; 7 | import InlineCode from './InlineCode'; 8 | import Link from './Link'; 9 | import Loading from '../../component/Loading/'; 10 | 11 | hljs.configure({ 12 | tabReplace: ' ', // 2 spaces 13 | classPrefix: '', // don't append class prefix 14 | }); 15 | 16 | const formatPath = path => 17 | path.replace(/^(\/|\\)/, '') 18 | .replace(/\.md$/, '') 19 | .replace(/\\/g, '/') 20 | .split('/') 21 | .join('___'); 22 | 23 | export default class Markdown extends React.Component { 24 | constructor(props) { 25 | super(props); 26 | this.state = { 27 | markdownStr: '', 28 | }; 29 | } 30 | componentWillMount() { 31 | this.renderMarkdown(); 32 | } 33 | renderMarkdown() { 34 | const { props: { type, relative } } = this.props; 35 | const relativeMd = relative; 36 | if (!relativeMd) return null; 37 | let filename = formatPath(relativeMd); 38 | if (type === 'directory') { 39 | filename = formatPath(relativeMd); 40 | } 41 | import(`__project_root__/.cache/md/${filename}.md`).then((data) => { 42 | this.setState({ 43 | markdownStr: data.default || data, 44 | }, () => { 45 | let code = ReactDOM.findDOMNode(this); 46 | code = code.getElementsByTagName('code'); 47 | for (let i = 0; i < code.length; i += 1) { 48 | if (code[i].parentNode && code[i].parentNode.tagName === 'PRE') { 49 | hljs.highlightBlock(code[i]); 50 | } 51 | } 52 | }); 53 | }); 54 | } 55 | render() { 56 | const { mdconf: { title, layout } } = this.props; 57 | const { markdownStr } = this.state; 58 | return ( 59 |
60 | {title && layout !== 'IndexLayout' &&

{title}

} 61 | {markdownStr ? ( 62 | { 72 | if (node.type === 'html') { 73 | // if (//.test(node.value)) return false; 74 | // const scriptValue = node.value.match(/(.*?)<\/script>/ig); 75 | // node.value.replace(/(.*?)<\/script>/, (te) => { 76 | // console.log('te:', te); 77 | // }); 78 | } 79 | // 判断 上一个节点是否为 80 | if (node.type === 'code' && parent.children && parent.children.length > 0 && parent.children[index - 1]) { 81 | const parentNode = parent.children[index - 1]; 82 | if (parentNode.type === 'html' && //.test(parentNode.value)) { 83 | node.value = `__dome__${node.value}`; 84 | } 85 | } 86 | return node; 87 | }} 88 | /> 89 | ) : ( 90 | 91 | )} 92 |
93 | ); 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /src/web/Router.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { HashRouter, withRouter, Route, Switch } from 'react-router-dom'; 3 | import lazyload from 'react-dynamic-loadable'; 4 | import theme from 'rdoc-theme'; 5 | import menuSource from './rdoc.tree.data.json'; 6 | 7 | // 判断目录下是否存在 README.md 8 | // 存在返回路由属性,表示是一个路由 9 | function directoryIsRoute(arr, props = false) { 10 | if (!arr || arr.length === 0) return false; 11 | const index = arr.filter(item => item.name === 'README.md' && item.mdconf); 12 | if (index && index.length > 0) props = { ...index[0] }; 13 | return props; 14 | } 15 | // 路由数据序列化 16 | function routeData(data, arrayRoute = [], routePath = '/', article) { 17 | data.forEach((item) => { 18 | const routeProps = directoryIsRoute(item.children); 19 | const routePropsCurrent = `${routePath}${item.name}`.replace(/.md$/, ''); 20 | if (item.type === 'directory' && routeProps) { 21 | const { mdconf, ...otherItem } = routeProps; 22 | arrayRoute.push({ 23 | path: routePropsCurrent, 24 | mdconf: mdconf || {}, 25 | props: { ...otherItem }, 26 | article: article || item.name, 27 | }); 28 | } else { 29 | const { mdconf, ...otherItem } = item; 30 | arrayRoute.push({ 31 | path: routePropsCurrent, 32 | mdconf: mdconf || { title: item.name }, 33 | props: { ...otherItem }, 34 | article: article || item.name, 35 | }); 36 | } 37 | if (item.children && item.children.length > 0) { 38 | arrayRoute.concat(routeData(item.children, arrayRoute, `${routePropsCurrent}/`, article || item.name)); 39 | } 40 | }); 41 | return arrayRoute; 42 | } 43 | 44 | 45 | function menuSourceFormat(data, routePath, article) { 46 | const arr = []; 47 | data.forEach((item) => { 48 | const routePropsCurrent = `${routePath || ''}/${item.name}`.replace(/.md$/, ''); 49 | if (item.type === 'directory') { 50 | const getDirReadmeProps = directoryIsRoute(item.children); 51 | if (item.children && item.children.length > 0 && getDirReadmeProps) { 52 | const { sort, title, mdconf, ...otherItem } = getDirReadmeProps; 53 | item.mdconf = mdconf || {}; 54 | item.props = otherItem || { isEmpty: true }; 55 | item.sort = mdconf.sort ? mdconf.sort : 0; 56 | item.children = menuSourceFormat(item.children, routePropsCurrent, article || item.name); 57 | } else { 58 | item.mdconf = { title: item.name }; 59 | item.props = { isEmpty: true }; 60 | item.sort = 0; 61 | item.children = []; 62 | } 63 | } else { 64 | item.title = item.mdconf && item.mdconf.title ? item.mdconf.title : item.name.replace(item.extension, ''); 65 | item.sort = item.mdconf && item.mdconf.sort ? item.mdconf.sort : 0; 66 | if (!item.mdconf) { 67 | item.props = { isEmpty: true }; 68 | } 69 | } 70 | item.routePath = routePropsCurrent; 71 | item.article = article || item.name; 72 | arr.push(item); 73 | }); 74 | return arr; 75 | } 76 | 77 | const RoutersContainer = withRouter(({ ...props }) => { 78 | const passProps = { 79 | routeData: routeData(menuSource), 80 | menuSource: menuSourceFormat(menuSource), 81 | ...props, 82 | }; 83 | return ( 84 | 85 | theme(lazyload, { ...routeProps, ...passProps })} /> 86 | 87 | ); 88 | }); 89 | 90 | export default function RouterRoot() { 91 | return ( 92 | 93 | 94 | 95 | ); 96 | } 97 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rdoc", 3 | "version": "1.12.0", 4 | "description": "Blazing-fast static site generator for React, Just write Markdown file.", 5 | "homepage": "https://react-doc.github.io", 6 | "bin": { 7 | "rdoc": ".bin/rdoc.js", 8 | "rdoc-cli": ".bin/rdoc.js" 9 | }, 10 | "scripts": { 11 | "release": "release-it --src.tagName='v%s'", 12 | "deploy": "node .bin/rdoc.js --publish git@github.com:react-doc/react-doc.github.io.git --branch master", 13 | "start": "node .bin/rdoc.js -d templates/default/home,templates/default/introduce,templates/default/faq,templates/default/about,templates/default/github --clean", 14 | "build": "node .bin/rdoc.js -d templates/default/home,templates/default/introduce,templates/default/faq,templates/default/about,templates/default/github --clean --build" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/jaywcjlove/rdoc.git" 19 | }, 20 | "keywords": [ 21 | "rdoc", 22 | "react", 23 | "react-doc" 24 | ], 25 | "author": "Kenny Wang", 26 | "license": "MIT", 27 | "dependencies": { 28 | "@babel/cli": "7.2.3", 29 | "@babel/core": "7.3.4", 30 | "@babel/plugin-proposal-class-properties": "7.3.4", 31 | "@babel/plugin-syntax-dynamic-import": "7.2.0", 32 | "@babel/plugin-syntax-object-rest-spread": "7.2.0", 33 | "@babel/plugin-transform-async-to-generator": "7.3.4", 34 | "@babel/plugin-transform-runtime": "7.3.4", 35 | "@babel/polyfill": "7.2.5", 36 | "@babel/preset-env": "7.3.4", 37 | "@babel/preset-react": "7.0.0", 38 | "@babel/runtime": "7.3.4", 39 | "@nuxtjs/friendly-errors-webpack-plugin": "2.0.2", 40 | "babel-eslint": "10.0.1", 41 | "babel-loader": "8.0.5", 42 | "classnames": "2.2.6", 43 | "colors-cli": "1.0.13", 44 | "commander": "2.12.2", 45 | "copy-markdown-image-webpack-plugin": "2.0.0", 46 | "copy-template-dir": "1.3.0", 47 | "create-spare-webpack-plugin": "2.0.0", 48 | "css-loader": "0.28.7", 49 | "detect-port": "1.2.2", 50 | "directory-tree-md": "2.0.7", 51 | "eslint": "4.19.1", 52 | "eslint-config-airbnb": "16.1.0", 53 | "eslint-loader": "2.0.0", 54 | "eslint-plugin-import": "2.11.0", 55 | "eslint-plugin-jsx-a11y": "6.0.3", 56 | "eslint-plugin-react": "7.7.0", 57 | "file-loader": "1.1.11", 58 | "fs-extra": "5.0.0", 59 | "gh-pages": "1.2.0", 60 | "highlight.js": "9.12.0", 61 | "html-webpack-plugin": "3.2.0", 62 | "less": "3.0.2", 63 | "less-loader": "4.1.0", 64 | "loading-cli": "1.0.6", 65 | "local-ip-url": "1.0.1", 66 | "mini-css-extract-plugin": "0.4.0", 67 | "open-browsers": "1.1.1", 68 | "optimize-css-assets-webpack-plugin": "4.0.0", 69 | "postcss-flexbugs-fixes": "3.2.0", 70 | "postcss-loader": "2.0.9", 71 | "raw-content-replace-loader": "1.0.1", 72 | "raw-extend-loader": "1.0.5", 73 | "raw-tree-replace-loader": "1.1.0", 74 | "react": "16.8.4", 75 | "react-document-title": "2.0.3", 76 | "react-dom": "16.8.4", 77 | "react-dynamic-loadable": "1.1.2", 78 | "react-hot-loader": "4.1.1", 79 | "react-markdown": "3.3.0", 80 | "react-router-dom": "4.2.2", 81 | "rimraf": "2.6.2", 82 | "string-replace-loader": "2.1.1", 83 | "style-loader": "0.19.1", 84 | "uglifyjs-webpack-plugin": "2.1.1", 85 | "upath": "1.0.2", 86 | "url-replace-loader": "1.0.0", 87 | "webpack": "4.40.2", 88 | "webpack-dev-middleware": "3.7.1", 89 | "webpack-dev-server": "3.8.1", 90 | "webpack-hot-dev-clients": "1.0.4", 91 | "webpackbar": "4.0.0", 92 | "write": "1.0.3" 93 | }, 94 | "devDependencies": { 95 | "release-it": "10.1.0" 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/conf/webpack.config.js: -------------------------------------------------------------------------------- 1 | const PATH = require('path'); 2 | const webpack = require('webpack'); 3 | const WebpackBar = require('webpackbar'); 4 | const UPATH = require('upath'); 5 | const paths = require('./path'); 6 | const pkg = require('../../package.json'); 7 | 8 | const define = { FOOTER: null }; 9 | if (paths.rdocConf && paths.rdocConf.footer && typeof paths.rdocConf.footer === 'string') { 10 | define.FOOTER = JSON.stringify(paths.rdocConf.footer); 11 | } 12 | 13 | module.exports = { 14 | entry: {}, 15 | output: { 16 | path: paths.appBuildDist, 17 | publicPath: paths.publicPath, 18 | filename: 'js/[name].[hash:8].js', 19 | chunkFilename: 'js/[name].[hash:8].js', 20 | }, 21 | resolve: { 22 | alias: { 23 | 'rdoc-theme': UPATH.normalizeSafe(paths.appThemePath), 24 | }, 25 | }, 26 | module: { 27 | rules: [ 28 | { 29 | test: /\.(js|jsx|mjs)$/, 30 | exclude: [/node_modules/, /\.(cache)/, /rdoc-theme-(.*)/], 31 | enforce: 'pre', 32 | use: [ 33 | // TODO:禁用require.ensure也不是一种标准的语言特征。 34 | // 我们等待https://github.com/facebookincubator/create-react-app/issues/2176。 35 | // { parser: { requireEnsure: false } }, 36 | { 37 | // 首先运行linter。 38 | // 在Babel处理js之前做这一点很重要。 39 | options: { 40 | eslintPath: require.resolve('eslint'), 41 | configFile: require.resolve('../../.eslintrc.js'), 42 | }, 43 | loader: require.resolve('eslint-loader'), 44 | }, 45 | ], 46 | }, 47 | { 48 | // “oneOf”将遍历所有以下加载程序,直到一个符合要求。 49 | // 当没有加载器匹配时,它将返回到加载程序列表末尾的“file”加载器。 50 | oneOf: [ 51 | { 52 | test: /\.(svg|png|bmp|jpg|jpeg|gif)$/, 53 | loader: require.resolve('url-replace-loader'), 54 | options: { 55 | limit: 10000, 56 | name: 'img/[name].[hash:8].[ext]', 57 | replace: [ 58 | { 59 | test: /rdoc\.logo\.svg$/, 60 | path: paths.logoPath, 61 | }, 62 | ], 63 | }, 64 | }, 65 | { 66 | test: /\.md$/, 67 | use: [ 68 | { 69 | loader: require.resolve('raw-content-replace-loader'), 70 | options: { 71 | path: PATH.join(paths.catchDirPath, './md'), // 需要替换的目录 72 | replace: paths.projectPath, // 替换成目标目录 73 | sep: /___/g, // 文件名存储,文件夹+下划线间隔+文件名 74 | }, 75 | }, 76 | ], 77 | }, 78 | // “file-loader”确保这些资源由WebpackDevServer服务。 79 | // 当您导入资源时,您将获得(虚拟)文件名。 80 | // 在生产中,它们将被复制到`build`文件夹。 81 | // 此加载程序不使用“test”,因此它将捕获所有模块 82 | { 83 | // 排除`js`文件以保持“css”加载器工作,因为它注入它的运行时,否则将通过“文件”加载器处理。 84 | // 还可以排除“html”和“json”扩展名,以便它们被webpacks内部加载器处理。 85 | exclude: [/\.js$/, /\.html$/, /\.json$/], 86 | loader: require.resolve('file-loader'), 87 | options: { 88 | name: 'static/[name].[hash:8].[ext]', 89 | }, 90 | }, 91 | ], 92 | }, 93 | ], 94 | }, 95 | plugins: [ 96 | new WebpackBar({ name: pkg.name }), 97 | new webpack.DefinePlugin({ 98 | VERSION: JSON.stringify(pkg.version), 99 | ...define, 100 | }), 101 | ], 102 | node: { 103 | dgram: 'empty', 104 | fs: 'empty', 105 | net: 'empty', 106 | tls: 'empty', 107 | child_process: 'empty', 108 | }, 109 | }; 110 | -------------------------------------------------------------------------------- /theme/default/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import { Switch, Route } from 'react-router-dom'; 3 | import DocumentTitle from 'react-document-title'; 4 | import BasicLayout from './layout/BasicLayout'; 5 | import IndexLayout from './layout/IndexLayout'; 6 | import NoMatch from './component/NoMatch'; 7 | import Loading from './component/Loading'; 8 | 9 | import './index.less'; 10 | 11 | // 获取首页路由参数 12 | // Markdown 配置 layout = 'IndexLayout' 13 | const getIndexProps = (menus = [], attr) => { 14 | menus.forEach((item) => { 15 | if (item && item.mdconf && item.mdconf.layout === 'IndexLayout') { 16 | attr = item; 17 | } 18 | if (!attr && item.children && item.children.length > 0) { 19 | attr = getIndexProps(item.children, attr); 20 | } 21 | }); 22 | return attr; 23 | }; 24 | 25 | export default function (Lazyload, props) { 26 | let indexRoute = null; 27 | 28 | const LoadableComponent = Lazyload({ 29 | component: () => import('./routes/Pages'), 30 | LoadingComponent: Loading, 31 | }); 32 | 33 | // 路由加载Component 34 | if (props.routeData && props.routeData.length > 0) { 35 | props.routeData.map((item) => { 36 | item.component = LoadableComponent; 37 | return item; 38 | }); 39 | } 40 | // 首页路由 41 | // 获取自定义路由 42 | let indexProps = getIndexProps(props.menuSource) || {}; 43 | if (indexProps) { 44 | props.routeData = props.routeData.filter(item => item.mdconf && item.mdconf.layout !== 'IndexLayout'); 45 | } else { 46 | // 未定义首页,默认第一个路由当首页 47 | indexProps = props.routeData.find((item, index) => index === 0); 48 | if (indexProps) indexProps.mdconf.layout = 'IndexLayout'; 49 | } 50 | 51 | const indexItem = { 52 | path: '/', 53 | mdconf: { ...indexProps.mdconf, layout: 'IndexLayout' }, 54 | props: { ...indexProps.props }, 55 | article: indexProps.article, 56 | }; 57 | 58 | // 首页路由放置路由数组中生成路由 59 | props.routeData.unshift({ 60 | ...indexItem, 61 | component: LoadableComponent, 62 | }); 63 | 64 | // 获取首页路由 65 | indexRoute = props.routeData.filter(item => item.mdconf && item.mdconf.layout === 'IndexLayout'); 66 | 67 | return ( 68 | 69 | ( 72 | 73 | 74 | 75 | )} 76 | /> 77 | { 79 | const { location: { pathname } } = routeProps; 80 | routeProps.indexProps = indexItem; 81 | let curentRoute = props.routeData.filter(item => item.path === pathname); 82 | let title = []; 83 | if (curentRoute.length > 0) { 84 | curentRoute = curentRoute[0]; 85 | if (curentRoute.mdconf && curentRoute.mdconf.title && curentRoute.mdconf.layout !== 'IndexLayout') { 86 | title.push(curentRoute.mdconf.title); 87 | } 88 | if (indexItem.mdconf && indexItem.mdconf.title) { 89 | title.push(indexItem.mdconf.title); 90 | } 91 | title = title.length > 1 ? title.join(' - ') : title.join(''); 92 | } else { 93 | title = '404'; 94 | } 95 | return ( 96 | 97 | {pathname === '/' ? 98 | : 99 | 100 | } 101 | 102 | ); 103 | }} 104 | /> 105 | 106 | ); 107 | } 108 | -------------------------------------------------------------------------------- /templates/default/home/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | 62 |
63 |
64 |
RDoc
65 |
RDoc 是一个文档生成工具,用于生成文档网站或简单的博客网站。
简单到你只需写 Markdown 文件就可以帮助你生成网站。
同时可以方便的集成到你的项目工程中。
66 | 快速开始 67 |
68 |
69 |
70 | 71 | 在开始之前,推荐先学习 Markdown 语法,并正确安装和配置了 [Node.js](https://nodejs.org) v8.0 或以上。 72 | 73 | 主要用于快速生成文档工具或简单的网站,只需要写Markdown文件既可。 74 | 75 | ```bash 76 | npm install rdoc -g # 安装工具 77 | # /usr/local/bin/rdoc -> /usr/local/lib/node_modules/rdoc/.bin/rdoc.js 78 | # /usr/local/bin/rdoc-cli -> /usr/local/lib/node_modules/rdoc/.bin/rdoc.js 79 | 80 | rdoc init my-project # 初始化项目 81 | # 也可以使用 rdoc-cli 命令,跟 rdoc 命令是一样的 82 | # 增加 用 rdoc-cli 命令,目的是解决 Mac 系统自带的 Ruby 命令 rdoc 冲突 83 | 84 | cd my-project && npm start # 进入工程,启动服务 85 | ``` 86 | 87 | ### Command 88 | 89 | ```shell 90 | Usage: rdoc [options] 91 | 92 | Fast static site generator for React. 93 | 94 | Options: 95 | 96 | -i, init [path] Create an empty website or reinitialize an existing one. 97 | -d, --doc Other documents generated. 98 | -o, --output Writes the compiled file to the disk directory. (default: .rdoc-dist) 99 | -p, --port [number] The port. (default: 5858) 100 | --host [host] The host. (default: 0.0.0.0) 101 | -b, --branch Name of the branch you are pushing to. (default: gh-pages) 102 | --publish [url] Other documents generated. 103 | --build Creating an optimized production build. 104 | --clean Delete the .cache folder. 105 | -h, --help output usage information 106 | 107 | Examples: 108 | 109 | $ rdoc init 110 | $ rdoc init doc-example 111 | $ rdoc -d doc/mm 112 | $ rdoc -d tutorial,doc 113 | $ rdoc -d tutorial,doc --clean --build 114 | $ rdoc -p 2323 -d doc --clean 115 | $ rdoc --host 0.0.0.0 -d doc --clean 116 | $ rdoc --publish https://.git --branch master 117 | ``` 118 | -------------------------------------------------------------------------------- /src/conf/path.js: -------------------------------------------------------------------------------- 1 | const PATH = require('path'); 2 | const FS = require('fs'); 3 | 4 | // 确保在项目文件夹中的任何符号都解决了: 5 | const appDirectory = FS.realpathSync(process.cwd()); 6 | const toolDirectory = FS.realpathSync(__dirname); 7 | // Markdown 所在目录 8 | const resolveApp = relativePath => PATH.resolve(appDirectory, relativePath); 9 | // rdoc 工具所在目录 10 | const resolveTool = relativePath => PATH.resolve(toolDirectory, relativePath); 11 | 12 | // 获取 rdoc 配置 13 | function getRdocConf() { 14 | const packagePath = resolveApp('./package.json'); 15 | let conf = {}; 16 | if (FS.existsSync(packagePath)) { 17 | const confPkg = require(packagePath); // eslint-disable-line 18 | conf = confPkg.rdoc; 19 | } 20 | const confPath = resolveApp('./.rdocrc.json'); 21 | if (FS.existsSync(confPath)) { 22 | const confRc = require(confPath) // eslint-disable-line 23 | conf = confRc; 24 | } 25 | return conf; 26 | } 27 | 28 | function getConfigFilePath(fileName, type) { 29 | const conf = getRdocConf(); 30 | // 这里是读取配置 31 | if (conf && conf[type]) { 32 | // 主题目录加载 33 | if (type === 'theme') { 34 | if (!conf[type]) conf[type] = fileName; 35 | const _path = PATH.resolve(appDirectory, 'theme', conf[type]); 36 | const _NodeModulesPath = PATH.resolve(appDirectory, 'node_modules', conf[type]); 37 | if (FS.existsSync(_path)) { 38 | return FS.realpathSync(_path); 39 | } else if (FS.existsSync(_NodeModulesPath)) { 40 | return FS.realpathSync(_NodeModulesPath); 41 | } 42 | return false; 43 | } 44 | if (/^(favicon|logo)$/.test(type)) { 45 | return PATH.resolve(appDirectory, conf[type]); 46 | } 47 | } 48 | const _filepath = PATH.resolve(appDirectory, fileName); 49 | if (FS.existsSync(_filepath)) { 50 | // 默认根目录下的 favicon|logo 51 | return _filepath; 52 | } 53 | return false; 54 | } 55 | 56 | // Get favicon path 57 | const faviconPath = () => { 58 | const _path = getConfigFilePath('./favicon.ico', 'favicon'); 59 | if (_path) return _path; 60 | return resolveTool('../../theme/default/favicon.ico'); 61 | }; 62 | 63 | // Get logo path 64 | const logoPath = () => { 65 | const _path = getConfigFilePath('./logo.svg', 'logo'); 66 | if (_path) return _path; 67 | return false; 68 | }; 69 | 70 | // Get theme path 71 | const getThemePath = () => { 72 | const _path = getConfigFilePath('./default', 'theme'); 73 | if (_path) return _path; 74 | return resolveTool('../../theme/default'); 75 | }; 76 | 77 | const modPath = resolveApp('node_modules'); 78 | function getExcludeFoldersRegExp() { 79 | if (!FS.existsSync(modPath)) return []; 80 | let regxExc = FS.readdirSync(modPath); 81 | regxExc = regxExc.filter(item => !/rdoc(.*)/.test(item)); 82 | 83 | regxExc = regxExc.map((item) => { 84 | let rgxPath = `node_modules${PATH.sep}${item}`; 85 | if (PATH.sep === '\\') { 86 | rgxPath = `node_modules\\${PATH.sep}${item}`; 87 | } 88 | return new RegExp(rgxPath); 89 | }); 90 | return regxExc; 91 | } 92 | 93 | module.exports = { 94 | // Markdown 所在目录 95 | rdocConf: getRdocConf(), 96 | appThemePath: getThemePath(), 97 | appPackage: resolveApp('./package.json'), 98 | appNodeModules: resolveApp('node_modules'), 99 | appBuildDist: resolveApp('.rdoc-dist'), 100 | catchDirPath: resolveApp('.cache'), 101 | docTreePath: resolveApp('.cache/.reactdoc.tree.json'), 102 | watchFilePath: resolveApp('.cache/watch-dir.js'), 103 | projectPath: appDirectory, 104 | publicPath: '', 105 | logoPath: logoPath(), 106 | // rdoc 工具所在目录 107 | getExcludeFoldersRegExp: getExcludeFoldersRegExp(), 108 | rdocPackage: resolveTool('../../package.json'), 109 | defaultNodeModules: modPath, 110 | defaultTemplatePath: resolveTool('../../templates/default'), 111 | defaultFaviconPath: faviconPath(), 112 | defaultHTMLPath: resolveTool('../../theme/default/index.html'), 113 | appIndexJs: resolveTool('../web/index.js'), 114 | appDir: resolveTool('../web'), 115 | }; 116 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 | rdoc 8 | --- 9 | 10 | [![Join the chat at https://gitter.im/j-rdoc/Lobby](https://badges.gitter.im/j-rdoc/Lobby.svg)](https://gitter.im/j-rdoc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![](https://img.shields.io/github/issues/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/issues) [![](https://img.shields.io/github/forks/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/network) [![](https://img.shields.io/github/stars/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/stargazers) [![](https://img.shields.io/github/release/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/releases) [![jaywcjlove/sb](https://jaywcjlove.github.io/sb/lang/english.svg)](README.md) 11 | 12 | 基于React的快速静态网站生成器,你只需要写 Markdown 文档即可。访问 [react-doc.github.io](https://react-doc.github.io)网站获取更多信息。 13 | 14 | > 这个文档网站就是一个 [demo](https://react-doc.github.io) 实例。 15 | 16 |
17 | 18 |
19 | 20 | ## 开始 21 | 22 | **rdoc** 使用非常简单,只需将其它作为模块安装并运行即可创建您的网站。 23 | 24 | 让我们开始吧! 25 | 26 | ### 安装 27 | 28 | 安装 `rdoc` 到你系统的全局,您需要在本地开发计算机上使用 `Node >= 8`。 您可以使用 [n](https://github.com/tj/n#installation) 轻松切换不同项目之间的 Node 版本。 29 | 30 | 31 | ```bash 32 | npm install rdoc -g 33 | 34 | # /usr/local/bin/rdoc -> /usr/local/lib/node_modules/rdoc/.bin/rdoc.js 35 | # /usr/local/bin/rdoc-cli -> /usr/local/lib/node_modules/rdoc/.bin/rdoc.js 36 | ``` 37 | 38 | 增加了 `rdoc-cli` 命令来解决 Mac 集成 `rdoc` 命令冲突。 39 | 40 | 1. 初始化项目 41 | 42 | ```bash 43 | rdoc init my-project # Init project 44 | # 或者 45 | rdoc-cli init my-project 46 | ``` 47 | 48 | 2. 运行网站 49 | 50 | ```bash 51 | cd my-project && npm install # 进入目录安装依赖 52 | npm start # 启动服务。 53 | ``` 54 | 55 | 3. 编译输出静态HTML资源。 56 | 57 | ```bash 58 | npm run build 59 | ``` 60 | 61 | 4. 在 `package.json` 中配置部署 `URL`。 62 | 63 | ```js 64 | { 65 | "scripts": { 66 | "deploy": "rdoc --publish " 67 | ... 68 | }, 69 | ... 70 | } 71 | ``` 72 | 73 | 5. 部署到 Github `gh-pages` 分支。 74 | 75 | ```bash 76 | npm run deploy 77 | ``` 78 | 79 | ### 命令帮助 80 | 81 | ```shell 82 | Usage: rdoc [options] 83 | 84 | Fast static site generator for React. 85 | 86 | Options: 87 | 88 | -i, init [path] 创建一个空的网站或重新初始化一个现有网站。 89 | -d, --doc 生成指定其他文档。 90 | -o, --output 将编译的文件写入磁盘目录。(默认:.rdoc-dist) 91 | -p, --port [number] 端口。(默认: 5858) 92 | --host [host] 主机. (默认: 0.0.0.0) 93 | -b, --branch <分支>您要推送的分支的名称。(默认:gh-pages) 94 | --publish [url] 将生成的代码,push到指定仓库,已经分支。 95 | --build 创建编译的生产版本。 96 | --clean 删除.cache文件夹。 97 | -h, --help 输出使用帮助文档。 98 | 99 | Examples: 100 | 101 | $ rdoc init 102 | $ rdoc init doc-example 103 | $ rdoc -d doc/mm 104 | $ rdoc -d tutorial,doc 105 | $ rdoc -d tutorial,doc --clean --build 106 | $ rdoc -p 2323 -d doc --clean 107 | $ rdoc --host 0.0.0.0 -d doc --clean 108 | $ rdoc --publish https://.git --branch master 109 | ``` 110 | ### 开发 111 | 112 | 获取代码,进入目录,运行自动重载构建,: 113 | 114 | ```shell 115 | $ git clone https://github.com/jaywcjlove/rdoc.git 116 | $ cd rdoc # 进入目录 117 | $ npm install # or yarn install 118 | ``` 119 | 120 | 要开发,请运行自重载构建: 121 | 122 | ```bash 123 | # 运行应用程序 124 | # 每次代码更改时,自动重新启动应用程序。 125 | # 在开发过程中很有用。 126 | $ npm run start 127 | ``` 128 | 129 | 打开浏览器并访问 http://localhost:5858 130 | 131 | ### Folders 132 | 133 | ```bash 134 | . 135 | ├── README.md 136 | ├── .rdoc-dist 137 | ├── package.json 138 | ├── src 139 | │   ├── build.js 140 | │   ├── commands 141 | │   ├── conf 142 | │   ├── publish.js 143 | │   ├── server.js 144 | │   ├── utils 145 | │   └── web 146 | ├── templates 147 | │   └── default # 记录静态文件。 148 | └── theme 149 | └── default 150 | ``` 151 | 152 | ### License 153 | 154 | The MIT License (MIT) 155 | -------------------------------------------------------------------------------- /theme/default/lib/markdown/style/default.less: -------------------------------------------------------------------------------- 1 | 2 | code { 3 | font-family: "SFMono-Regular", Consolas, "Liberation Mono", Menlo, Courier, monospace; 4 | word-wrap: normal; 5 | } 6 | code:not(.hljs){ 7 | padding: 0.2em 0.4em; 8 | margin: 0; 9 | font-size: 85%; 10 | background-color: rgba(27, 31, 35, 0.07); 11 | border-radius: 3px; 12 | } 13 | code.hljs { 14 | padding: 16px; 15 | font-size: 95%; 16 | line-height: 1.5; 17 | display: block; 18 | text-shadow: 0 1px #fff; 19 | } 20 | pre { 21 | max-height: 35em; 22 | position: relative; 23 | overflow: auto; 24 | background-color: #F0F0F0; 25 | border-radius: 3px; 26 | } 27 | pre code { 28 | background: none; 29 | font-size: 1em; 30 | overflow-wrap: normal; 31 | white-space: inherit; 32 | } 33 | ul, ol { 34 | padding-left: 2em; 35 | } 36 | dl { 37 | padding: 0; 38 | dt { 39 | padding: 0; 40 | margin-top: 16px; 41 | font-size: 14px; 42 | font-style: italic; 43 | font-weight: 600; 44 | } 45 | } 46 | li + li { 47 | margin-top: 3px; 48 | } 49 | a { 50 | color: #0366d6; 51 | } 52 | p { 53 | margin-bottom: 16px; 54 | } 55 | blockquote { 56 | margin: 0; 57 | padding: 0 1em; 58 | margin: 16px 0 16px 0; 59 | color: #6a737d; 60 | border-left: 0.25em solid #dfe2e5; 61 | & >:first-child { 62 | margin-top: 0; 63 | } 64 | & >:last-child { 65 | margin-bottom: 0; 66 | } 67 | } 68 | hr { 69 | height: 0.25em; 70 | padding: 0; 71 | margin: 24px 0; 72 | background-color: #e1e4e8; 73 | border: 0; 74 | } 75 | 76 | h1 tt,h1 code,h2 tt,h2 code,h3 tt,h3 code,h4 tt,h4 code,h5 tt,h5 code,h6 tt,h6 code { 77 | font-size: inherit 78 | } 79 | 80 | h1 { 81 | padding-bottom: 0.3em; 82 | font-size: 2em; 83 | border-bottom: 1px solid #eaecef 84 | } 85 | 86 | h2 { 87 | padding-bottom: 0.3em; 88 | font-size: 1.5em; 89 | border-bottom: 1px solid #eaecef 90 | } 91 | 92 | h3 { 93 | font-size: 1.25em 94 | } 95 | 96 | h4 { 97 | font-size: 1em 98 | } 99 | 100 | h5 { 101 | font-size: 0.875em 102 | } 103 | 104 | h6 { 105 | font-size: 0.85em; 106 | color: #6a737d 107 | } 108 | 109 | table { 110 | border-collapse: collapse; 111 | border-spacing: 0; 112 | width: 100%; 113 | & + table { 114 | margin-top: 16px; 115 | } 116 | } 117 | 118 | table th { 119 | font-weight: 600; 120 | white-space: nowrap; 121 | color: #5c6b77; 122 | background: rgba(0,0,0,.02); 123 | } 124 | 125 | table th,table td { 126 | padding: 8px 13px; 127 | border: 1px solid #dfe2e5; 128 | } 129 | 130 | table tr { 131 | background-color: #fff; 132 | border-top: 1px solid #c6cbd1; 133 | } 134 | 135 | table tr:nth-child(2n) { 136 | background-color: #f6f8fa; 137 | } 138 | 139 | table img { 140 | background-color: transparent; 141 | } 142 | 143 | img { 144 | max-width: 100%; 145 | box-sizing: content-box; 146 | background-color: #fff; 147 | vertical-align: middle; 148 | } 149 | 150 | img[align=right] { 151 | padding-left: 20px; 152 | } 153 | 154 | img[align=left] { 155 | padding-right: 20px; 156 | } 157 | 158 | .comment,.quote{ 159 | color:#998; 160 | } 161 | .keyword,.selector-tag,.subst{ 162 | color:#333;font-weight:bold; 163 | } 164 | .number,.literal,.variable,.template-variable,.tag .attr{ 165 | color:#008080; 166 | } 167 | .string,.doctag{ 168 | color:#d14; 169 | } 170 | .title,.section,.selector-id{ 171 | color:#900;font-weight:bold; 172 | } 173 | .subst{ 174 | font-weight:normal; 175 | } 176 | .type,.class .title{ 177 | color:#458;font-weight:bold; 178 | } 179 | .tag,.name,.attribute{ 180 | color:#000098; 181 | font-weight:normal; 182 | } 183 | .regexp,.link{ 184 | color:#009926; 185 | } 186 | .symbol,.bullet{ 187 | color:#990073; 188 | } 189 | .built_in,.builtin-name{ 190 | color:#0086b3; 191 | } 192 | .meta{ 193 | color:#999;font-weight:bold; 194 | } 195 | .deletion{ 196 | background:#fdd; 197 | } 198 | .addition{ 199 | background:#dfd; 200 | } 201 | .emphasis{ 202 | font-style:italic; 203 | } 204 | .strong{ 205 | font-weight:bold; 206 | } 207 | 208 | -------------------------------------------------------------------------------- /src/conf/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const webpack = require('webpack'); 3 | const PATH = require('path'); 4 | const UPATH = require('upath'); 5 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 6 | const CreateSpareWebpackPlugin = require('create-spare-webpack-plugin'); 7 | const FriendlyErrorsWebpackPlugin = require('@nuxtjs/friendly-errors-webpack-plugin'); 8 | const config = require('./webpack.config'); 9 | const paths = require('./path'); 10 | 11 | module.exports = function (cmd) { 12 | config.mode = 'development'; 13 | config.entry = [ 14 | require.resolve('react-hot-loader/patch'), 15 | require.resolve('webpack-hot-dev-clients/webpackHotDevClient'), 16 | paths.appIndexJs, 17 | ]; 18 | config.module.rules = config.module.rules.map((item) => { 19 | if (item.oneOf) { 20 | const loaders = []; 21 | loaders.push({ 22 | // Process JS with Babel. 23 | test: /\.(js|jsx|mjs)$/, 24 | exclude: paths.getExcludeFoldersRegExp.concat(/\.(cache)/), 25 | use: [ 26 | { 27 | loader: require.resolve('string-replace-loader'), 28 | options: { 29 | multiple: [ 30 | { search: '__project_root__', replace: UPATH.normalizeSafe(paths.projectPath), flags: 'ig' }, 31 | ], 32 | }, 33 | }, 34 | { 35 | loader: require.resolve('babel-loader'), 36 | options: require('../../.babelrc'), // eslint-disable-line 37 | }, 38 | ], 39 | }); 40 | // https://ilikekillnerds.com/2018/03/disable-webpack-4-native-json-loader/ 41 | loaders.push({ 42 | test: /rdoc\.tree\.data\.json$/, 43 | // 禁用Webpack 4本身的JSON加载程序 44 | type: 'javascript/auto', 45 | use: [ 46 | { 47 | loader: require.resolve('raw-tree-replace-loader'), 48 | options: { 49 | include: /rdoc\.tree\.data\.json$/, // 检查包含的文件名字 50 | directoryTrees: { // 指定目录生成目录树,json 51 | dir: cmd.markdownPaths, 52 | mdconf: true, 53 | extensions: /\.md/, 54 | relativePath: true, 55 | }, 56 | }, 57 | }, 58 | ], 59 | }); 60 | 61 | loaders.push({ 62 | test: /\.(css|less)$/, 63 | use: [ 64 | require.resolve('style-loader'), 65 | { 66 | loader: require.resolve('css-loader'), 67 | options: { 68 | modules: true, 69 | localIdentName: '[name]-[hash:base64:5]', 70 | importLoaders: 1, 71 | }, 72 | }, 73 | { 74 | loader: require.resolve('postcss-loader'), 75 | options: { 76 | // Necessary for external CSS imports to work 77 | // https://github.com/facebookincubator/create-react-app/issues/2677 78 | ident: 'postcss', 79 | plugins: () => [ 80 | require('postcss-flexbugs-fixes'), // eslint-disable-line 81 | autoprefixer({ 82 | browsers: [ 83 | '>1%', 84 | 'last 4 versions', 85 | 'Firefox ESR', 86 | 'not ie < 9', // React doesn't support IE8 anyway 87 | ], 88 | flexbox: 'no-2009', 89 | }), 90 | ], 91 | }, 92 | }, 93 | require.resolve('less-loader'), 94 | ], 95 | }); 96 | 97 | item.oneOf = loaders.concat(item.oneOf); 98 | } 99 | return item; 100 | }); 101 | 102 | config.plugins = config.plugins.concat([ 103 | new webpack.HotModuleReplacementPlugin(), 104 | new HtmlWebpackPlugin({ 105 | inject: true, 106 | favicon: paths.defaultFaviconPath, 107 | template: paths.defaultHTMLPath, 108 | title: paths.rdocConf && paths.rdocConf.title ? paths.rdocConf.title : 'Rdoc', 109 | }), 110 | // 将模块名称添加到工厂功能,以便它们显示在浏览器分析器中。 111 | // 当接收到热更新信号时,在浏览器console控制台打印更多可读性高的模块名称等信息 112 | new webpack.NamedModulesPlugin(), 113 | new CreateSpareWebpackPlugin({ 114 | // 备用文件目录,比对是否存在,不存在生成,根据sep 目录规则生成 115 | path: PATH.join(paths.catchDirPath, './md'), 116 | sep: '___', // 检查目标目录文件,文件名存储,文件夹+下划线间隔+文件名 117 | directoryTrees: { // 索引目录 118 | dir: cmd.markdownPaths, 119 | mdconf: true, 120 | extensions: /\.md$/, 121 | }, 122 | }), 123 | new FriendlyErrorsWebpackPlugin({ 124 | clearConsole: true, 125 | }), 126 | ]); 127 | return config; 128 | }; 129 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 |

6 | 7 | rdoc 8 | --- 9 | 10 | [![Join the chat at https://gitter.im/j-rdoc/Lobby](https://badges.gitter.im/j-rdoc/Lobby.svg)](https://gitter.im/j-rdoc/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![](https://img.shields.io/github/issues/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/issues) [![](https://img.shields.io/github/forks/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/network) [![](https://img.shields.io/github/stars/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/stargazers) [![](https://img.shields.io/github/release/jaywcjlove/rdoc.svg)](https://github.com/jaywcjlove/rdoc/releases) [![jaywcjlove/sb](https://jaywcjlove.github.io/sb/lang/chinese.svg)](README_zh.md) 11 | 12 | Blazing-fast static site generator for React, Just write Markdown file. Visit the [react-doc.github.io](https://react-doc.github.io) website for more information. 13 | 14 | > The documentation site is also a demo [example](https://react-doc.github.io). 15 | 16 |
17 | 18 |
19 | 20 | ## Getting Started 21 | 22 | It's really easy to get started with **rdoc**. Just install it as a module and run it to create your website. 23 | 24 | Let's get you started! 25 | 26 | ### Install 27 | 28 | Install `rdoc` globally on your system. You’ll need to have Node >= 8 on your local development machine. You can use [n](https://github.com/tj/n#installation) to easily switch Node versions between different projects. 29 | 30 | ```bash 31 | npm install rdoc -g 32 | 33 | # /usr/local/bin/rdoc -> /usr/local/lib/node_modules/rdoc/.bin/rdoc.js 34 | # /usr/local/bin/rdoc-cli -> /usr/local/lib/node_modules/rdoc/.bin/rdoc.js 35 | ``` 36 | 37 | Added `rdoc-cli` command to resolve Mac integration `rdoc` command conflicts. 38 | 39 | 1. Init Project 40 | 41 | ```bash 42 | rdoc init my-project # Init project 43 | # or 44 | rdoc-cli init my-project 45 | ``` 46 | 47 | 2. Run website 48 | 49 | ```bash 50 | cd my-project && npm install # Install dependencies. 51 | npm start # Into the directory, start the service. 52 | ``` 53 | 54 | 3. Compile output static HTML resources 55 | 56 | ```bash 57 | npm run build 58 | ``` 59 | 60 | 4. Configure the deployment URL in `package.json` 61 | 62 | ```js 63 | { 64 | "scripts": { 65 | "deploy": "rdoc --publish " 66 | ... 67 | }, 68 | ... 69 | } 70 | ``` 71 | 72 | 5. Deploy to Github's `gh-pages` branch 73 | 74 | ```bash 75 | npm run deploy 76 | ``` 77 | 78 | ### Command 79 | 80 | ```shell 81 | Usage: rdoc [options] 82 | 83 | Fast static site generator for React. 84 | 85 | Options: 86 | 87 | -i, init [path] Create an empty website or reinitialize an existing one. 88 | -d, --doc Other documents generated. 89 | -o, --output Writes the compiled file to the disk directory. (default: .rdoc-dist) 90 | -p, --port [number] The port. (default: 5858) 91 | --host [host] The host. (default: 0.0.0.0) 92 | -b, --branch Name of the branch you are pushing to. (default: gh-pages) 93 | --publish [url] Other documents generated. 94 | --build Creating an optimized production build. 95 | --clean Delete the .cache folder. 96 | -h, --help output usage information 97 | 98 | Examples: 99 | 100 | $ rdoc init 101 | $ rdoc init doc-example 102 | $ rdoc -d doc/mm 103 | $ rdoc -d tutorial,doc 104 | $ rdoc -d tutorial,doc --clean --build 105 | $ rdoc -p 2323 -d doc --clean 106 | $ rdoc --host 0.0.0.0 -d doc --clean 107 | $ rdoc --publish https://.git --branch master 108 | ``` 109 | ### Development 110 | 111 | To develop, run the self-reloading build, Get the code: 112 | 113 | ```shell 114 | $ git clone https://github.com/jaywcjlove/rdoc.git 115 | $ cd rdoc # Into the directory 116 | $ npm install # or yarn install 117 | ``` 118 | 119 | To develop, run the self-reloading build: 120 | 121 | ```bash 122 | # Run the app 123 | # Restart the app automatically every time code changes. 124 | # Useful during development. 125 | $ npm run start 126 | ``` 127 | 128 | Open your browser and visit http://localhost:5858 129 | 130 | ### Folders 131 | 132 | ```bash 133 | . 134 | ├── README.md 135 | ├── .rdoc-dist 136 | ├── package.json 137 | ├── src 138 | │   ├── build.js 139 | │   ├── commands 140 | │   ├── conf 141 | │   ├── publish.js 142 | │   ├── server.js 143 | │   ├── utils 144 | │   └── web 145 | ├── templates 146 | │   └── default # document the static file. 147 | └── theme 148 | └── default 149 | ``` 150 | 151 | ### License 152 | 153 | The MIT License (MIT) 154 | -------------------------------------------------------------------------------- /theme/default/layout/BasicLayout.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import { Switch, Link, Route, Redirect } from 'react-router-dom'; 3 | import classNames from 'classnames'; 4 | import styles from './BasicLayout.less'; 5 | import Header from '../component/Header'; 6 | import Footer from '../component/Footer'; 7 | import logo from '../rdoc.logo.svg'; 8 | 9 | function getCurrentArticle(routeData, path) { 10 | let article = null; 11 | routeData.forEach((item) => { 12 | if (item.path === path) { 13 | article = item.article; 14 | } 15 | }); 16 | return article; 17 | } 18 | 19 | export default class BasicLayout extends PureComponent { 20 | constructor(props) { 21 | super(props); 22 | this.state = {}; 23 | } 24 | componentDidUpdate() { 25 | this.scrollToTop(); 26 | } 27 | componentDidMount() { 28 | this.scrollToTop(); 29 | } 30 | scrollToTop() { 31 | document.body.scrollTop = 0; 32 | document.documentElement.scrollTop = 0; 33 | window.scrollTo(0, 0); 34 | } 35 | renderSubMenuItem(menus) { 36 | const { location: { pathname } } = this.props; 37 | if (menus.length > 1) { 38 | menus = menus.sort((a, b) => { 39 | if (a.sort < b.sort) return -1; 40 | if (a.sort > b.sort) return 1; 41 | return 0; 42 | }); 43 | } 44 | return ( 45 |
    46 | { 47 | menus.map((item, index) => { 48 | if (item.isEmpty) { 49 | return null; 50 | } 51 | if (item.children && item.children.length < 1) return null; 52 | if (item.props && item.props.visible === true) return null; 53 | if (/^README(.*)md$/.test(item.name)) return null; 54 | return ( 55 |
  • 56 |
    57 | {item && item.props && (item.props.redirect || item.props.isEmpty) ?
    {(item.mdconf && item.mdconf.title) || ''}
    : ( 58 | 59 | {item && item.mdconf.title ? item.mdconf.title : item.name} 60 | 61 | )} 62 |
    63 | {item.children && item.children.length > 0 && this.renderSubMenuItem(item.children)} 64 |
  • 65 | ); 66 | }) 67 | } 68 |
69 | ); 70 | } 71 | renderSubMenu(menus) { 72 | const { location: { pathname }, routeData } = this.props; 73 | const article = getCurrentArticle(routeData, pathname); 74 | menus = menus.filter(item => item.article === article); 75 | if (menus.length < 1) return null; 76 | const menusObject = menus[0] && menus[0].children ? menus[0].children : []; 77 | return this.renderSubMenuItem(menusObject); 78 | } 79 | isCurentChildren() { 80 | const { location: { pathname }, menuSource, routeData } = this.props; 81 | const getRoute = routeData.filter(item => pathname === item.path); 82 | const article = getRoute.length > 0 ? getRoute[0].article : null; 83 | const childs = menuSource.filter(item => article === item.article && item.children && item.children.length > 1); 84 | return childs.length > 0; 85 | } 86 | render() { 87 | const { menuSource, routeData, indexProps } = this.props; 88 | const isChild = this.isCurentChildren(); 89 | return ( 90 |
91 |
92 |
93 | {isChild && ( 94 |
{this.renderSubMenu(menuSource)}
95 | )} 96 |
101 | 102 | {routeData.map((item) => { 103 | // 重定向跳转 104 | if (item && item.mdconf && item.mdconf.redirect) { 105 | let redirectPath = `${item.path || ''}/${item.mdconf.redirect}`; 106 | redirectPath = redirectPath.replace(/^\/\//, '/'); 107 | return ( 108 | } /> 109 | ); 110 | } 111 | return ( 112 | { 116 | const Comp = item.component; 117 | return ; 118 | }} 119 | /> 120 | ); 121 | })} 122 | 123 | 124 |
125 |
126 |
127 |
128 | ); 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /src/conf/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const autoprefixer = require('autoprefixer'); 2 | const PATH = require('path'); 3 | const UPATH = require('upath'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const CreateSpareWebpackPlugin = require('create-spare-webpack-plugin'); 6 | const CopyMarkdownImageWebpackPlugin = require('copy-markdown-image-webpack-plugin'); 7 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 8 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 9 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 10 | const config = require('./webpack.config'); 11 | const paths = require('./path'); 12 | 13 | module.exports = function (cmd) { 14 | config.mode = 'production'; 15 | config.entry = [paths.appIndexJs]; 16 | config.output.filename = 'js/[hash:8].js'; 17 | config.output.chunkFilename = 'js/[name].[hash:8].js'; 18 | config.module.rules = config.module.rules.map((item) => { 19 | if (item.oneOf) { 20 | const loaders = []; 21 | loaders.push({ 22 | // Process JS with Babel. 23 | test: /\.(js|jsx|mjs)$/, 24 | exclude: paths.getExcludeFoldersRegExp.concat(/\.(cache)/), 25 | use: [ 26 | { 27 | loader: require.resolve('string-replace-loader'), 28 | options: { 29 | multiple: [ 30 | { search: '__project_root__', replace: UPATH.normalizeSafe(paths.projectPath), flags: 'ig' }, 31 | ], 32 | }, 33 | }, 34 | { 35 | loader: require.resolve('babel-loader'), 36 | options: require('../../.babelrc'), // eslint-disable-line 37 | }, 38 | ], 39 | }); 40 | // https://ilikekillnerds.com/2018/03/disable-webpack-4-native-json-loader/ 41 | loaders.push({ 42 | test: /rdoc\.tree\.data\.json$/, 43 | // 禁用Webpack 4本身的JSON加载程序 44 | type: 'javascript/auto', 45 | use: [ 46 | { 47 | loader: require.resolve('raw-tree-replace-loader'), 48 | options: { 49 | include: /rdoc\.tree\.data\.json$/, // 检查包含的文件名字 50 | directoryTrees: { // 指定目录生成目录树,json 51 | dir: cmd.markdownPaths, 52 | mdconf: true, 53 | extensions: /\.md/, 54 | relativePath: true, 55 | }, 56 | }, 57 | }, 58 | ], 59 | }); 60 | 61 | loaders.push({ 62 | test: /\.(css|less)$/, 63 | use: [ 64 | MiniCssExtractPlugin.loader, 65 | { 66 | loader: require.resolve('css-loader'), 67 | options: { 68 | modules: true, 69 | localIdentName: '[name]-[hash:base64:5]', 70 | importLoaders: 1, 71 | }, 72 | }, 73 | { 74 | loader: require.resolve('postcss-loader'), 75 | options: { 76 | // Necessary for external CSS imports to work 77 | // https://github.com/facebookincubator/create-react-app/issues/2677 78 | ident: 'postcss', 79 | plugins: () => [ 80 | require('postcss-flexbugs-fixes'), // eslint-disable-line 81 | autoprefixer({ 82 | browsers: [ 83 | '>1%', 84 | 'last 4 versions', 85 | 'Firefox ESR', 86 | 'not ie < 9', // React doesn't support IE8 anyway 87 | ], 88 | flexbox: 'no-2009', 89 | }), 90 | ], 91 | }, 92 | }, 93 | require.resolve('less-loader'), 94 | ], 95 | }); 96 | 97 | item.oneOf = loaders.concat(item.oneOf); 98 | } 99 | return item; 100 | }); 101 | config.optimization = { 102 | runtimeChunk: true, 103 | minimizer: [ 104 | new UglifyJsPlugin({ 105 | cache: true, 106 | parallel: true, 107 | sourceMap: true, // set to true if you want JS source maps 108 | }), 109 | new OptimizeCSSAssetsPlugin({}), 110 | ], 111 | splitChunks: { 112 | minSize: 0, 113 | chunks: 'initial', 114 | cacheGroups: { 115 | commons: { 116 | chunks: 'initial', 117 | minChunks: 2, 118 | maxInitialRequests: 5, // The default limit is too small to showcase the effect 119 | minSize: 2000, // This is example is too small to create commons chunks 120 | }, 121 | vendor: { 122 | test: /node_modules/, 123 | chunks: 'initial', 124 | name: 'vendor', 125 | priority: 10, 126 | enforce: true, 127 | }, 128 | }, 129 | }, 130 | }; 131 | 132 | config.plugins = config.plugins.concat([ 133 | new HtmlWebpackPlugin({ 134 | inject: true, 135 | favicon: paths.defaultFaviconPath, 136 | template: paths.defaultHTMLPath, 137 | title: paths.rdocConf && paths.rdocConf.title ? paths.rdocConf.title : 'Rdoc', 138 | minify: { 139 | removeAttributeQuotes: true, 140 | collapseWhitespace: true, 141 | html5: true, 142 | minifyCSS: true, 143 | removeComments: true, 144 | removeEmptyAttributes: true, 145 | }, 146 | }), 147 | new CopyMarkdownImageWebpackPlugin({ 148 | dir: cmd.markdownPaths, 149 | toDir: config.output.path, 150 | }), 151 | new CreateSpareWebpackPlugin({ 152 | // 备用文件目录,比对是否存在,不存在生成,根据sep 目录规则生成 153 | path: PATH.join(paths.catchDirPath, './md'), 154 | sep: '___', // 检查目标目录文件,文件名存储,文件夹+下划线间隔+文件名 155 | directoryTrees: { // 索引目录 156 | dir: cmd.markdownPaths, 157 | mdconf: true, 158 | extensions: /\.md$/, 159 | }, 160 | }), 161 | // new webpack.optimize.DedupePlugin(), 162 | new MiniCssExtractPlugin({ 163 | // Options similar to the same options in webpackOptions.output 164 | // both options are optional 165 | filename: 'css/[contenthash].css', 166 | chunkFilename: 'css/[id].css', 167 | }), 168 | ]); 169 | return config; 170 | }; 171 | -------------------------------------------------------------------------------- /theme/default/component/Header/index.js: -------------------------------------------------------------------------------- 1 | import React, { PureComponent } from 'react'; 2 | import classNames from 'classnames'; 3 | import { Link } from 'react-router-dom'; 4 | import PropTypes from 'prop-types'; 5 | import styles from './index.less'; 6 | 7 | const SVGGithub = ( 8 | 9 | 10 | 11 | ); 12 | 13 | const isString = val => typeof val === 'string'; 14 | 15 | export default class Header extends PureComponent { 16 | renderTopMenu(menuSource, pathname) { 17 | if (menuSource.length > 1) { 18 | menuSource = menuSource.sort((a, b) => { 19 | if (a.sort < b.sort) return -1; 20 | if (a.sort > b.sort) return 1; 21 | return 0; 22 | }); 23 | } 24 | return menuSource.map((item, index) => { 25 | if (!item) return null; 26 | if (item.mdconf && item.mdconf.visible === true) return null; 27 | 28 | const url = item.mdconf && (item.mdconf.github || item.mdconf.url); 29 | if (url) { 30 | return ( 31 | 32 | {item.mdconf.github && SVGGithub}{item.mdconf.title && {item.mdconf.title}} 33 | 34 | ); 35 | } 36 | if (item.props && item.props.isEmpty === true && (item.mdconf && !item.mdconf.redirect)) return null; 37 | 38 | const regx = new RegExp(`^/${item.name}`, 'g'); 39 | const isActive = regx.test(pathname); 40 | return ( 41 | 42 | {item.mdconf.title || item.name} 43 | 44 | ); 45 | }); 46 | } 47 | render() { 48 | const { location: { pathname }, menuSource, className, children, logo } = this.props; 49 | const { mdconf } = this.props.indexProps || {}; 50 | return ( 51 |
52 |
53 |
{logo && logo}{mdconf.title}
54 | {menuSource &&
{this.renderTopMenu(menuSource, pathname)}
} 55 | {children && children.map((item, index) => { 56 | if (isString(item)) return item; 57 | return React.cloneElement(item, { key: index }); 58 | })} 59 |
60 |
61 | ); 62 | } 63 | } 64 | 65 | Header.propTypes = { 66 | logo: PropTypes.oneOfType([PropTypes.string, PropTypes.element]), 67 | menuSource: PropTypes.array, 68 | }; 69 | 70 | Header.defaultProps = { 71 | logo: null, 72 | menuSource: [], 73 | }; 74 | -------------------------------------------------------------------------------- /templates/default/introduce/api/theme-api.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ## 全局变量 7 | 8 | 全局变量 `__project_root__` 通常用于模板中懒加载 `markdown` 文件,例如: 9 | 10 | > 生成的缓存序列化文件,将被存放到当前目录下的 `.cache/md` 目录中。 11 | 12 | ```js 13 | // 加载高亮库 14 | import hljs from 'highlight.js'; 15 | 16 | // filename 处理很重要 17 | // Markdown文件被处理成 `doc___fed___react___component-and-props.md` 这样, 18 | // 路径以下划线间隔避免重复,所以 要获取路径得 通过 props.page.routeData 中获取 relative 路径来处理 19 | const filename = ''; 20 | // 加载 Markdown 文件, 21 | import(`__project_root__/.cache/md/${filename}.md`).then((data) => { 22 | this.setState({ 23 | markdown: data, 24 | }, () => { 25 | // 找到当前组件根节点,循环code, 26 | // 对code里面的代码进行高亮 27 | let code = ReactDOM.findDOMNode(this); 28 | code = code.getElementsByTagName('code'); 29 | for (let i = 0; i < code.length; i += 1) { 30 | if (code[i].parentNode && code[i].parentNode.tagName === 'PRE') { 31 | hljs.highlightBlock(code[i]); 32 | } 33 | } 34 | }); 35 | }); 36 | ``` 37 | 38 | ## Markdown 文件索引 39 | 40 | 那你需要建立一个 `替身` 文件 `rdoc.tree.data.json`,引用替身文件,就可以获取到目录索引内容,这个在编译的时候会自动返回文件索引的 `json`。 41 | 42 | > ⚠️ 替身文件名字,必须取名 `rdoc.tree.data.json`。 43 | > ⚠️ 这个文件是必须建立,引用,这样可以渲染菜单。 44 | > ⚠️ rdoc v1.3.0 以后版本不需要,如果你有同名文件会被替换成,Markdown 文件索引。 45 | > ⚠️ Markdown 文件索引,会在入口函数传入。 46 | 47 | ```js 48 | import menuSource from './rdoc.tree.data.json'; 49 | ``` 50 | 51 | ## 模板入口 52 | 53 | ```js 54 | import BaseLayout from './layout/BasicLayout'; 55 | import Loading from './component/Loading'; 56 | 57 | export default function (Lazyload, props) { 58 | if (props.routeData && props.routeData.length > 0) { 59 | props.routeData.map((item) => { 60 | item.component = Lazyload({ 61 | component: () => import('./routes/Pages'), 62 | LoadingComponent: Loading, 63 | }); 64 | return item; 65 | }); 66 | } 67 | return ; 68 | } 69 | ``` 70 | 71 | ## 两个入口参数 72 | 73 | `props` 提供路由索引,和 Markdown 文件索引信息。`Lazyload` 为懒加载方法。 74 | 75 | ### Lazyload 76 | 77 | 文档工具包 [react-dynamic-loadable](https://github.com/jaywcjlove/react-dynamic-loadable) 提供的,懒加载方法,下面方法为路由添加 `component` 并传入相应参数。 78 | 79 | ```js 80 | props.routeData.map((item) => { 81 | item.component = Lazyload({ 82 | component: () => import('./routes/Pages'), 83 | LoadingComponent: Loading, 84 | }); 85 | return item; 86 | }); 87 | ``` 88 | 89 | ### props 90 | 91 | ```js 92 | { 93 | history: {length: 50, action: "POP", location: {…}, createHref: ƒ, push: ƒ, …}, 94 | location: {pathname: "/introduce/api/theme-api", search: "", hash: "", state: undefined}, 95 | match: {path: "/", url: "/", params: {…}, isExact: false}, 96 | menuSource: [{…}, {…}, {…}, {…}, {…}], 97 | routeData: [{…}, {…}, {…}, {…}, {…}], 98 | staticContext: undefined 99 | } 100 | ``` 101 | 102 | #### props.menuSource 103 | 104 | > path 你 Markdown 的全路径 105 | > name 文件夹或者文件的名称 106 | > type 当前节点是一个文件夹还是一个文件`file|directory` 107 | > extension 类型为`file`的后缀 108 | 109 | > **根据文件索引出来的参数** 110 | > 111 | > relative 相对于你指定的路径 112 | > routePath 路由路径 113 | > isEmpty 114 | > size 文件大小 115 | > mdconf 是你在 Markdown中定义的参数 116 | 117 | > **Markdown手动配置的参数** 118 | > 119 | > sort 排序 120 | > title 标题 121 | > visible 是否隐藏菜单 122 | 123 | ```json 124 | [ 125 | { 126 | "path": "/Users/mac/doc-example/index", 127 | "name": "index", 128 | "children": [ 129 | { 130 | "path": "/Users/mac/doc-example/index/README.md", 131 | "name": "README.md", 132 | "relative": "/index/README.md", 133 | "mdconf": { 134 | "title": "首页", 135 | "layout": "IndexLayout", 136 | "visible": "true", 137 | "logo": "/introduce/assets/react-logo.svg" 138 | }, 139 | "isEmpty": false, 140 | "size": 1821, 141 | "extension": ".md", 142 | "type": "file", 143 | "title": "首页", 144 | "sort": 0, 145 | "routePath": "/index/README", 146 | "article": "index" 147 | } 148 | ], 149 | "size": 1821, 150 | "type": "directory", 151 | "mdconf": { 152 | "title": "首页", 153 | "layout": "IndexLayout", 154 | "visible": "true", 155 | "logo": "/introduce/assets/react-logo.svg" 156 | }, 157 | "props": { 158 | "path": "/Users/mac/doc-example/index/README.md", 159 | "name": "README.md", 160 | "relative": "/index/README.md", 161 | "isEmpty": false, 162 | "size": 1821, 163 | "extension": ".md", 164 | "type": "file" 165 | }, 166 | "sort": 0, 167 | "routePath": "/index", 168 | "article": "index" 169 | } 170 | ] 171 | ``` 172 | 173 | #### props.routeData 174 | 175 | > props 文档配置及其信息 176 | > path 路由信息,配合 `React Router` 使用 177 | > relative 路径,从项目的,根目录开始,主要用于读取 Markdown 组合 Markdown 的文件名字 178 | 179 | ```json 180 | [ 181 | { 182 | "path": "/introduce/api", 183 | "mdconf": { 184 | "title": "API", 185 | "sort": "3" 186 | }, 187 | "props": { 188 | "path": "/Users/mac/doc-example/introduce/api/README.md", 189 | "name": "README.md", 190 | "relative": "/introduce/api/README.md", 191 | "isEmpty": true, 192 | "size": 27, 193 | "extension": ".md", 194 | "type": "file" 195 | }, 196 | "article": "introduce", 197 | "title": "" 198 | },{ 199 | "path": "/index", 200 | "mdconf": { 201 | "title": "首页", 202 | "layout": "IndexLayout", 203 | "visible": "true", 204 | "logo": "/introduce/assets/react-logo.svg" 205 | }, 206 | "props": { 207 | "path": "/Users/mac/doc-example/index/README.md", 208 | "name": "README.md", 209 | "relative": "/index/README.md", 210 | "isEmpty": false, 211 | "size": 1821, 212 | "extension": ".md", 213 | "type": "file" 214 | }, 215 | "article": "index", 216 | "title": "" 217 | }, 218 | ] 219 | ``` 220 | 221 | ## BaseLayout 222 | 223 | 这个是定于的主框架模板,俗称通用布局,主要用于定制头部右边,不常变换的内容,你可以定义多个 `Layout`, 例如你定义 `Markdown` 参数,根据参数加载不用样式的通用布局。 224 | 225 | 226 | ## 默认依赖包 227 | 228 | 工具基础的前端包工具,制作主题需要安装依赖包,提供一个实例 [rdoc-theme-load-react](https://github.com/react-doc/rdoc-theme-load-react)。 229 | 230 | ```bash 231 | { 232 | "classnames": "2.2.5", 233 | "highlight.js": "9.12.0", 234 | "prop-types": "15.6.0", 235 | "react": "16.2.0", 236 | "react-dom": "16.2.0", 237 | "react-markdown": "3.1.3", 238 | "react-router-dom": "4.2.2", 239 | } 240 | ``` 241 | -------------------------------------------------------------------------------- /templates/default/introduce/guides/theme.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | 通过自定义主题来定义网站前端内容。下面定义主题的步骤: 7 | 8 | ## 创建主题 9 | 10 | ```bash 11 | mkdir rdoc-theme-load-react # 创建主题目录 12 | npm init -y # 生成配置文件 package.json 13 | ``` 14 | 15 | ⚠️ 注意事项:主题必须以 `rdoc-theme-` 开头,否则会报错。 16 | 17 | 生成 `package.json` 内容: 18 | 19 | ```json 20 | { 21 | "name": "rdoc-theme-load-react", 22 | "version": "1.0.0", 23 | "description": "", 24 | "main": "index.js", 25 | "scripts": { 26 | "test": "echo \"Error: no test specified\" && exit 1" 27 | }, 28 | "keywords": [], 29 | "author": "", 30 | "license": "MIT" 31 | } 32 | ``` 33 | 34 | ## 添加主题文件 35 | 36 | ```bash 37 | ├── README.md # 说明文档 38 | ├── lib # 主题文件编译后的文件 39 | ├── package.json 40 | └── src # 没有编译的js文件 41 | ``` 42 | 43 | 可以将默认主题拷贝到 `src` 目录中,基于[默认主题](https://github.com/jaywcjlove/rdoc/tree/master/theme/default)来改一个新的主题。 44 | 45 | ## 添加编译命令 46 | 47 | 主题文件建立好之后,通过 `babel` 来编译你的主题,将编译后的文件存储到 `lib` 目录中,添加编译命令,通过 `npm run build` 去编译你的代码。 48 | 49 | 安装依赖 50 | 51 | ```shell 52 | npm install --save-dev babel-cli babel-core babel-eslint babel-plugin-syntax-dynamic-import babel-plugin-transform-async-to-generator babel-plugin-transform-class-properties babel-plugin-transform-object-rest-spread babel-plugin-transform-runtime babel-preset-env babel-preset-react 53 | ``` 54 | 55 | 56 | ```diff 57 | { 58 | "name": "rdoc-theme-load-react", 59 | "version": "1.0.0", 60 | "description": "", 61 | + "main": "lib/index.js", 62 | - "main": "index.js", 63 | "scripts": { 64 | + "build": "BABEL_ENV=production babel --ignore=src/**/__test__ --plugins transform-runtime src --out-dir lib --copy-files ", 65 | - "test": "echo \"Error: no test specified\" && exit 1" 66 | }, 67 | "keywords": [], 68 | "author": "", 69 | + "devDependencies": { 70 | + "babel-cli": "^6.26.0", 71 | + "babel-core": "^6.26.3", 72 | + "babel-eslint": "^8.2.3", 73 | + "babel-plugin-syntax-dynamic-import": "^6.18.0", 74 | + "babel-plugin-transform-async-to-generator": "^6.24.1", 75 | + "babel-plugin-transform-class-properties": "^6.24.1", 76 | + "babel-plugin-transform-object-rest-spread": "^6.26.0", 77 | + "babel-plugin-transform-runtime": "^6.23.0", 78 | + "babel-preset-env": "^1.6.1" 79 | + }, 80 | "license": "MIT" 81 | } 82 | ``` 83 | 84 | 添加babel配置文件 `.babelrc`。 85 | 86 | ```json 87 | { 88 | "presets": [ 89 | "env", 90 | "react" 91 | ], 92 | "plugins": [ 93 | "transform-object-rest-spread", 94 | "syntax-dynamic-import", 95 | "transform-async-to-generator", 96 | "transform-class-properties", 97 | "transform-runtime" 98 | ] 99 | } 100 | ``` 101 | 102 | 通过运行命令编译主题 103 | 104 | ```bash 105 | npm run build 106 | ``` 107 | 108 | ## 添加实时编译命令 109 | 110 | 添加监听模式下开发你的主题,你不能写一句代码,运行一下 `npm run start` 去编译你的代码,要实时编译你的代码,所以你要添加一个实时编译参数。 111 | 112 | ```diff 113 | { 114 | "name": "rdoc-theme-load-react", 115 | "version": "1.0.0", 116 | "description": "", 117 | "main": "lib/index.js", 118 | "scripts": { 119 | "build": "BABEL_ENV=production babel --ignore=src/**/__test__ --plugins transform-runtime src --out-dir lib --copy-files ", 120 | + "dev": "BABEL_ENV=production babel -w --ignore=src/**/__test__ --plugins transform-runtime src --out-dir lib --copy-files ", 121 | + "start": "npm run dev" 122 | }, 123 | "keywords": [], 124 | "author": "", 125 | "devDependencies": { 126 | "babel-cli": "^6.26.0", 127 | "babel-core": "^6.26.3", 128 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 129 | "babel-plugin-transform-async-to-generator": "^6.24.1", 130 | "babel-plugin-transform-class-properties": "^6.24.1", 131 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 132 | "babel-plugin-transform-runtime": "^6.23.0", 133 | "babel-preset-env": "^1.6.1" 134 | }, 135 | "license": "MIT" 136 | } 137 | ``` 138 | 139 | 通过运行命令,实时编译主题 140 | 141 | ```bash 142 | npm run start 143 | ``` 144 | 145 | ## 添加代码检测 146 | 147 | 安装代码检测依赖工具 148 | 149 | ```bash 150 | npm install --save-dev eslint eslint-config-airbnb eslint-plugin-import eslint-plugin-jsx-a11y eslint-plugin-react eslint-watch 151 | ``` 152 | 153 | 添加对应的代码检测命令 154 | 155 | ```diff 156 | { 157 | "name": "rdoc-theme-load-react", 158 | "version": "1.0.0", 159 | "description": "", 160 | "main": "lib/index.js", 161 | "scripts": { 162 | "build": "BABEL_ENV=production babel --ignore=src/**/__test__ --plugins transform-runtime src --out-dir lib --copy-files ", 163 | "dev": "BABEL_ENV=production babel -w --ignore=src/**/__test__ --plugins transform-runtime src --out-dir lib --copy-files ", 164 | - "start": "npm run dev" 165 | + "start": "npm run dev & npm run lint:watch", 166 | + "lint": "NODE_ENV=production eslint src", 167 | + "lint:watch": "esw -w src", 168 | + "test": "npm run lint" 169 | }, 170 | "keywords": [], 171 | "author": "", 172 | "devDependencies": { 173 | "babel-cli": "^6.26.0", 174 | "babel-core": "^6.26.3", 175 | "babel-plugin-syntax-dynamic-import": "^6.18.0", 176 | "babel-plugin-transform-async-to-generator": "^6.24.1", 177 | "babel-plugin-transform-class-properties": "^6.24.1", 178 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 179 | "babel-plugin-transform-runtime": "^6.23.0", 180 | "babel-preset-env": "^1.6.1", 181 | + "eslint": "^4.19.1", 182 | + "eslint-config-airbnb": "^16.1.0", 183 | + "eslint-plugin-import": "^2.11.0", 184 | + "eslint-plugin-jsx-a11y": "^6.0.3", 185 | + "eslint-plugin-react": "^7.7.0", 186 | + "eslint-watch": "^3.1.4" 187 | }, 188 | "license": "MIT" 189 | } 190 | ``` 191 | 192 | 添加代码检查 ESLint 的配置文件 `.babelrc`。 193 | 194 | ```json 195 | { 196 | "parser": "babel-eslint", 197 | "extends": "airbnb", 198 | "env": { 199 | "browser": true, 200 | "node": true, 201 | "es6": true, 202 | "mocha": true, 203 | "jest": true, 204 | "jasmine": true 205 | }, 206 | "plugins": [ 207 | "react", 208 | "import" 209 | ], 210 | "parserOptions": { 211 | "parser": "babel-eslint" 212 | }, 213 | "rules": { 214 | "linebreak-style": 0, 215 | "func-names": 0, 216 | "sort-imports": 0, 217 | "arrow-body-style": 0, 218 | "prefer-destructuring": 0, 219 | "max-len": 0, 220 | "consistent-return": 0, 221 | "comma-dangle": [ "error", "always-multiline" ], 222 | "function-paren-newline": 0, 223 | "class-methods-use-this": 0, 224 | "react/sort-comp": 0, 225 | "react/prop-types": 0, 226 | "react/jsx-first-prop-new-line": 0, 227 | "react/require-extension": 0, 228 | "react/jsx-filename-extension": [ 1, { "extensions": [ ".js", ".jsx" ] } ], 229 | "import/extensions": 0, 230 | "import/no-unresolved": 0, 231 | "import/no-extraneous-dependencies": 0, 232 | "import/prefer-default-export": 0, 233 | "jsx-a11y/no-static-element-interactions": 0, 234 | "jsx-a11y/anchor-has-content": 0, 235 | "jsx-a11y/click-events-have-key-events": 0, 236 | "jsx-a11y/anchor-is-valid": 0, 237 | "jsx-a11y/label-has-for": 0, 238 | "jsx-a11y/no-noninteractive-element-interactions": 0, 239 | "jsx-a11y/mouse-events-have-key-events": 0, 240 | "react/no-danger": 0, 241 | "react/jsx-no-bind": 0, 242 | "react/forbid-prop-types": 0, 243 | "react/require-default-props": 0, 244 | "react/no-did-mount-set-state": 0, 245 | "react/no-array-index-key": 0, 246 | "react/no-find-dom-node": 0, 247 | "react/no-unused-state": 0, 248 | "react/no-unused-prop-types": 0, 249 | "react/default-props-match-prop-types": 0, 250 | "react/jsx-curly-spacing": 0, 251 | "react/no-render-return-value": 0, 252 | "object-curly-newline": 0, 253 | "no-param-reassign": 0, 254 | "no-return-assign": 0, 255 | "no-redeclare": 0, 256 | "no-restricted-globals": 0, 257 | "no-restricted-syntax": 0, 258 | "no-underscore-dangle": 0, 259 | "no-unused-expressions": 0 260 | } 261 | } 262 | ``` 263 | 264 | ## 开发模式调试主题 265 | 266 | 在你通过上面步骤建立的主题目录下运行命令 267 | 268 | ```bash 269 | # 进入目录 270 | cd rdoc-theme-load-react 271 | # 将 rdoc-theme-load-react 安装到全局目录中 272 | npm link 273 | # /lib/node_modules/rdoc-theme-load-react -> ~/rdoc/rdoc-theme-load-react 274 | ``` 275 | 276 | 生成一个 `rdoc` 文档工程 277 | 278 | ```bash 279 | npm install -g rdoc # 全局安装 rdoc 工具 280 | rdoc init dochelp # 生成一个叫 dochelp 的工程 281 | ``` 282 | 283 | 安装你自定义的主题 `rdoc-theme-load-react` 284 | 285 | ```bash 286 | npm link rdoc-theme-load-react 287 | ``` 288 | 289 | 在 `dochelp` 工程的 `package.json` 中添加配置 290 | 291 | ```diff 292 | { 293 | "name": "dochelp", 294 | "version": "1.0.0", 295 | "description": "Describe rdoc-theme-load-react here", 296 | "private": true, 297 | "scripts": { 298 | "deploy": "rdoc --publish ", 299 | "build": "rdoc -d home,introduce,faq,about,github --clean --build", 300 | "start": "rdoc -d home,introduce,faq,about,github --clean" 301 | }, 302 | "keywords": [], 303 | + "rdoc": { 304 | + "theme": "rdoc-theme-load-react" 305 | + }, 306 | "dependencies": { 307 | "rdoc": "1.4.x" 308 | }, 309 | "author": "", 310 | "license": "MIT" 311 | } 312 | ``` 313 | 314 | ## 主题发布到npm 315 | 316 | 如果主题发布到外网,你可以将主题作为一个依赖来使用主题,首先你需要注册一个账号 http://npmjs.org/ ,在命令行中登录你的账号,或者直接在命令行通过 `npm` 命令注册账号。 317 | 318 | ```bash 319 | # 登录 npm 账号 320 | npm login 321 | # 进入主题的根目录 322 | cd rdoc-theme-load-react 323 | # 上传你的主题包,上传记得编译好你的主题哦 324 | npm publish 325 | ``` 326 | --------------------------------------------------------------------------------