├── .babelrc ├── .editorconfig ├── .gitignore ├── .npmignore ├── .prettierrc ├── CHANGELOG.md ├── LICENSE ├── README.md ├── docs ├── index.html └── index.js ├── less └── highlight.less ├── package.json ├── src ├── Markdown.js ├── index.js └── renderer.js ├── webpack.config.js └── yarn.lock /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "stage-0", 4 | "react", 5 | "es2015" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | 3 | root = true 4 | 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | Ï 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | 6 | # Runtime data 7 | pids 8 | *.pid 9 | *.seed 10 | 11 | # Directory for instrumented libs generated by jscoverage/JSCover 12 | lib-cov 13 | 14 | # Coverage directory used by tools like istanbul 15 | coverage 16 | 17 | # nyc test coverage 18 | .nyc_output 19 | 20 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 21 | .grunt 22 | 23 | # node-waf configuration 24 | .lock-wscript 25 | 26 | # Compiled binary addons (http://nodejs.org/api/addons.html) 27 | build/Release 28 | 29 | # Dependency directories 30 | node_modules 31 | jspm_packages 32 | 33 | # Optional npm cache directory 34 | .npm 35 | 36 | # Optional REPL history 37 | .node_repl_history 38 | 39 | .vscode/ 40 | lib/ -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | src/ 3 | dev/ 4 | dist/ 5 | .vscode/ 6 | examples/ 7 | assets 8 | karma* 9 | .idea/ 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "singleQuote": true 5 | } 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # 1.2.0 2 | 3 | - Update dependencies 4 | - Breaking marked@0.6.2 5 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Simon Guo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # react-markdown-reader 2 | 3 | ## Install 4 | 5 | ``` 6 | npm install html-loader --save-dev 7 | npm install markdown-loader --save-dev 8 | npm install react-markdown-reader --save-dev 9 | ``` 10 | 11 | ## Usage 12 | 13 | `webpack.config.js` 14 | 15 | **webpack >= 2** 16 | 17 | ```js 18 | const markdownRenderer = require('react-markdown-reader').renderer; 19 | 20 | { 21 | test: /\.md$/, 22 | use: [{ 23 | loader: 'html-loader' 24 | }, { 25 | loader: 'markdown-loader', 26 | options: { 27 | renderer: markdownRenderer(/**languages[string]**/) 28 | } 29 | }] 30 | } 31 | ``` 32 | 33 | 注意: markdownRenderer 参数 languages,是为了按需加载,解决加载所有的语言包文件过大的问题。默认值: 34 | 35 | ```js 36 | ['javascript', 'bash', 'xml', 'css', 'markdown', 'less']; 37 | ``` 38 | 39 | Exmaple 40 | 41 | ```js 42 | import { Markdown } from 'react-markdown-reader'; 43 | import 'react-markdown-reader/less/highlight.less'; 44 | 45 | {require('./README.md')}; 46 | ``` 47 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /docs/index.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | 4 | import Markdown from '../src/Markdown'; 5 | import '../less/highlight.less'; 6 | 7 | const App = () => { 8 | return {require('../README.md')}; 9 | }; 10 | 11 | ReactDOM.render(, document.getElementById('app')); 12 | -------------------------------------------------------------------------------- /less/highlight.less: -------------------------------------------------------------------------------- 1 | /* Tomorrow Comment */ 2 | .hljs-comment, 3 | .hljs-quote { 4 | color: #8e908c; 5 | } 6 | 7 | /* Tomorrow Red */ 8 | .hljs-variable, 9 | .hljs-template-variable, 10 | .hljs-tag, 11 | .hljs-name, 12 | .hljs-selector-id, 13 | .hljs-selector-class, 14 | .hljs-regexp, 15 | .hljs-deletion { 16 | color: #c82829; 17 | } 18 | 19 | /* Tomorrow Orange */ 20 | .hljs-number, 21 | .hljs-built_in, 22 | .hljs-builtin-name, 23 | .hljs-literal, 24 | .hljs-type, 25 | .hljs-params, 26 | .hljs-meta, 27 | .hljs-link { 28 | color: #f5871f; 29 | } 30 | 31 | /* Tomorrow Yellow */ 32 | .hljs-attribute { 33 | color: #eab700; 34 | } 35 | 36 | /* Tomorrow Green */ 37 | .hljs-string, 38 | .hljs-symbol, 39 | .hljs-bullet, 40 | .hljs-addition { 41 | color: #718c00; 42 | } 43 | 44 | /* Tomorrow Blue */ 45 | .hljs-title, 46 | .hljs-section { 47 | color: #4271ae; 48 | } 49 | 50 | /* Tomorrow Purple */ 51 | .hljs-keyword, 52 | .hljs-selector-tag { 53 | color: #8959a8; 54 | } 55 | 56 | .hljs { 57 | display: block; 58 | overflow-x: auto; 59 | background: white; 60 | color: #4d4d4c; 61 | padding: 0.5em; 62 | } 63 | 64 | .hljs-emphasis { 65 | font-style: italic; 66 | } 67 | 68 | .hljs-strong { 69 | font-weight: bold; 70 | } 71 | 72 | 73 | 74 | .markdown table { 75 | width: 100%; 76 | th { 77 | background: #f1f1f1; 78 | } 79 | td, th { 80 | border: 1px solid #eee; 81 | padding: 10px; 82 | } 83 | } 84 | 85 | pre { 86 | border: none; 87 | border-radius: 0; 88 | } 89 | 90 | code { 91 | border-radius: inherit; 92 | } 93 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-markdown-reader", 3 | "version": "1.2.0", 4 | "description": "markdown reader", 5 | "main": "lib/index.js", 6 | "scripts": { 7 | "dev": "NODE_ENV=development webpack-dev-server --inline --progress --colors --port 3100 --host 0.0.0.0 ", 8 | "build": "rm -rf lib && babel src --out-dir lib ", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "git+https://github.com/simonguo/react-markdown-reader.git" 14 | }, 15 | "files": [ 16 | "CHANGELOG.md", 17 | "lib" 18 | ], 19 | "keywords": [ 20 | "react", 21 | "webpack", 22 | "mackdown" 23 | ], 24 | "author": "simonguo.2009@gmail.com", 25 | "license": "MIT", 26 | "bugs": { 27 | "url": "https://github.com/simonguo/react-markdown-reader/issues" 28 | }, 29 | "homepage": "https://github.com/simonguo/react-markdown-reader#readme", 30 | "dependencies": { 31 | "highlight.js": "^9.4.0", 32 | "marked": "^0.6.2" 33 | }, 34 | "peerDependencies": { 35 | "react": "^0.14.9 || >=15.3.0" 36 | }, 37 | "devDependencies": { 38 | "babel-cli": "^6.26.0", 39 | "babel-core": "^6.7.6", 40 | "babel-eslint": "^6.1.2", 41 | "babel-loader": "^6.2.4", 42 | "babel-preset-es2015": "^6.6.0", 43 | "babel-preset-react": "^6.3.13", 44 | "babel-preset-stage-0": "^6.5.0", 45 | "compression-webpack-plugin": "^1.0.1", 46 | "css-loader": "^0.23.1", 47 | "extract-text-webpack-plugin": "^2.1.0", 48 | "html-loader": "^0.5.5", 49 | "html-webpack-plugin": "^2.22.0", 50 | "less": "^2.7.1", 51 | "less-loader": "^2.2.3", 52 | "markdown-loader": "^5.0.0", 53 | "react": "^16.4.2", 54 | "react-dom": "^16.4.2", 55 | "react-hot-loader": "^3.0.0-beta.6", 56 | "style-loader": "^0.13.1", 57 | "webpack": "^2.2.1", 58 | "webpack-dev-server": "^2.3.0" 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/Markdown.js: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | 3 | class Markdown extends React.Component { 4 | constructor() { 5 | super(); 6 | this.createMarkup = this.createMarkup.bind(this); 7 | } 8 | createMarkup() { 9 | return { __html: this.props.children }; 10 | } 11 | render() { 12 | return ( 13 |
17 | ); 18 | } 19 | } 20 | 21 | export default Markdown; 22 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | export Markdown from './Markdown'; 2 | export renderer from './renderer'; 3 | -------------------------------------------------------------------------------- /src/renderer.js: -------------------------------------------------------------------------------- 1 | const marked = require('marked'); 2 | const hl = require('highlight.js/lib/highlight'); 3 | const defalutLanguages = ['javascript', 'bash', 'xml', 'css', 'markdown', 'less']; 4 | 5 | export default (languages = defalutLanguages) => { 6 | languages.forEach(langName => { 7 | let langModule = require(`highlight.js/lib/languages/${langName}`); 8 | hl.registerLanguage(langName, langModule); 9 | }); 10 | 11 | const renderer = new marked.Renderer(); 12 | const codeRenderer = function(code, lang) { 13 | lang = lang === 'js' ? 'javascript' : lang; 14 | if (lang === 'html') { 15 | lang = 'xml'; 16 | } 17 | 18 | const hlCode = lang ? hl.highlight(lang, code).value : hl.highlightAuto(code).value; 19 | return `
${hlCode}
`; 21 | }; 22 | 23 | renderer.code = codeRenderer; 24 | 25 | return renderer; 26 | }; 27 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const webpack = require('webpack'); 3 | const HtmlwebpackPlugin = require('html-webpack-plugin'); 4 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 5 | const CompressionPlugin = require('compression-webpack-plugin'); 6 | const markdownRenderer = require('./lib/renderer')['default']; 7 | const { NODE_ENV } = process.env; 8 | 9 | const extractLess = new ExtractTextPlugin({ 10 | filename: '[name].[contenthash].css', 11 | disable: NODE_ENV === 'development' 12 | }); 13 | 14 | const docsPath = NODE_ENV === 'development' ? './assets' : './'; 15 | 16 | const plugins = [ 17 | new webpack.HotModuleReplacementPlugin(), 18 | new webpack.NamedModulesPlugin(), 19 | new webpack.DefinePlugin({ 20 | 'process.env': { 21 | NODE_ENV: JSON.stringify(NODE_ENV) 22 | } 23 | }), 24 | extractLess, 25 | new HtmlwebpackPlugin({ 26 | title: 'react code view', 27 | filename: 'index.html', 28 | template: 'docs/index.html', 29 | inject: true, 30 | hash: true, 31 | path: docsPath 32 | }) 33 | ]; 34 | 35 | if (process.env.NODE_ENV === 'production') { 36 | plugins.push(new webpack.optimize.UglifyJsPlugin()); 37 | plugins.push(new webpack.BannerPlugin({ banner: `Last update: ${new Date().toString()}` })); 38 | plugins.push( 39 | new CompressionPlugin({ 40 | asset: '[path].gz[query]', 41 | algorithm: 'gzip', 42 | test: /\.(js|html)$/, 43 | threshold: 10240, 44 | minRatio: 0.8 45 | }) 46 | ); 47 | } 48 | 49 | const common = { 50 | entry: path.resolve(__dirname, 'src/'), 51 | devServer: { 52 | hot: true, 53 | disableHostCheck: true, 54 | contentBase: path.resolve(__dirname, ''), 55 | publicPath: '/' 56 | }, 57 | output: { 58 | path: path.resolve(__dirname, 'assets'), 59 | filename: 'bundle.js', 60 | publicPath: './' 61 | }, 62 | plugins, 63 | module: { 64 | rules: [ 65 | { 66 | test: /\.jsx?$/, 67 | use: ['babel-loader'], 68 | exclude: /node_modules/ 69 | }, 70 | { 71 | test: /\.less$/, 72 | loader: extractLess.extract({ 73 | use: [ 74 | { 75 | loader: 'css-loader' 76 | }, 77 | { 78 | loader: 'less-loader' 79 | } 80 | ], 81 | // use style-loader in development 82 | fallback: 'style-loader' 83 | }) 84 | }, 85 | { 86 | test: /\.md$/, 87 | use: [ 88 | { 89 | loader: 'html-loader' 90 | }, 91 | { 92 | loader: 'markdown-loader', 93 | options: { 94 | renderer: markdownRenderer() 95 | } 96 | } 97 | ] 98 | } 99 | ] 100 | } 101 | }; 102 | 103 | module.exports = () => { 104 | if (NODE_ENV === 'development') { 105 | return Object.assign({}, common, { 106 | entry: [ 107 | 'react-hot-loader/patch', 108 | 'webpack-dev-server/client?http://127.0.0.1:3100', 109 | 'webpack/hot/only-dev-server', 110 | path.resolve(__dirname, 'docs/index') 111 | ], 112 | devtool: 'source-map' 113 | }); 114 | } 115 | 116 | return Object.assign({}, common, { 117 | entry: [path.resolve(__dirname, 'docs/index')] 118 | }); 119 | }; 120 | --------------------------------------------------------------------------------