211 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			211 lines
		
	
	
		
			5.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
| const path = require('path');
 | |
| const hljs = require('highlight.js');
 | |
| const Token = require('markdown-it/lib/token');
 | |
| const cheerio = require('cheerio');
 | |
| const WebpackBar = require('webpackbar');
 | |
| const VueLoaderPlugin = require('vue-loader/lib/plugin');
 | |
| const getBabelCommonConfig = require('./antd-tools/getBabelCommonConfig');
 | |
| const babelConfig = getBabelCommonConfig(false);
 | |
| 
 | |
| babelConfig.plugins.push(require.resolve('babel-plugin-syntax-dynamic-import'));
 | |
| 
 | |
| const fetch = (str, tag, scoped) => {
 | |
|   const $ = cheerio.load(str, {
 | |
|     decodeEntities: false,
 | |
|     xmlMode: true,
 | |
|   });
 | |
|   if (!tag) {
 | |
|     return str;
 | |
|   }
 | |
|   if (tag === 'style') {
 | |
|     return scoped
 | |
|       ? $(`${tag}[scoped]`).html()
 | |
|       : $(`${tag}`)
 | |
|           .not(`${tag}[scoped]`)
 | |
|           .html();
 | |
|   }
 | |
|   return $(tag).html();
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * `{{ }}` => `<span>{{</span> <span>}}</span>`
 | |
|  * @param  {string} str
 | |
|  * @return {string}
 | |
|  */
 | |
| const replaceDelimiters = function(str) {
 | |
|   return str.replace(/({{|}})/g, '<span>$1</span>');
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * renderHighlight
 | |
|  * @param  {string} str
 | |
|  * @param  {string} lang
 | |
|  */
 | |
| 
 | |
| const renderHighlight = function(str, lang) {
 | |
|   if (!(lang && hljs.getLanguage(lang))) {
 | |
|     return '';
 | |
|   }
 | |
| 
 | |
|   try {
 | |
|     return replaceDelimiters(hljs.highlight(lang, str, true).value);
 | |
|   } catch (err) {}
 | |
| };
 | |
| 
 | |
| const md = require('markdown-it')('default', {
 | |
|   html: true,
 | |
|   breaks: true,
 | |
|   highlight: renderHighlight,
 | |
| }).use(require('markdown-it-anchor'), {
 | |
|   level: 2,
 | |
|   slugify: string =>
 | |
|     string
 | |
|       .trim()
 | |
|       .split(' ')
 | |
|       .join('-'),
 | |
|   permalink: true,
 | |
|   // renderPermalink: (slug, opts, state, permalink) => {},
 | |
|   permalinkClass: 'anchor',
 | |
|   permalinkSymbol: '#',
 | |
|   permalinkBefore: false,
 | |
| });
 | |
| // md.renderer.rules.fence = wrap(md.renderer.rules.fence)
 | |
| const cnReg = new RegExp('<(cn)(?:[^<]|<)+</\\1>', 'g');
 | |
| const usReg = new RegExp('<(us)(?:[^<]|<)+</\\1>', 'g');
 | |
| md.core.ruler.push('update_template', function replace({ tokens }) {
 | |
|   let cn = '';
 | |
|   let us = '';
 | |
|   let template = '';
 | |
|   let script = '';
 | |
|   let style = '';
 | |
|   let scopedStyle = '';
 | |
|   let code = '';
 | |
|   let sourceCode = '';
 | |
|   tokens.forEach(token => {
 | |
|     if (token.type === 'html_block') {
 | |
|       if (token.content.match(cnReg)) {
 | |
|         cn = fetch(token.content, 'cn');
 | |
|         token.content = '';
 | |
|       }
 | |
|       if (token.content.match(usReg)) {
 | |
|         us = fetch(token.content, 'us');
 | |
|         token.content = '';
 | |
|       }
 | |
|     }
 | |
|     if (token.type === 'fence' && token.info === 'tpl' && token.markup === '```') {
 | |
|       sourceCode = token.content;
 | |
|       code = '````html\n' + token.content + '````';
 | |
|       template = fetch(token.content, 'template');
 | |
|       script = fetch(token.content, 'script');
 | |
|       style = fetch(token.content, 'style');
 | |
|       scopedStyle = fetch(token.content, 'style', true);
 | |
|       token.content = '';
 | |
|       token.type = 'html_block';
 | |
|     }
 | |
|   });
 | |
|   if (template) {
 | |
|     let jsfiddle = {
 | |
|       html: template,
 | |
|       script,
 | |
|       style,
 | |
|       us,
 | |
|       cn,
 | |
|       sourceCode,
 | |
|     };
 | |
|     jsfiddle = md.utils.escapeHtml(JSON.stringify(jsfiddle));
 | |
|     const codeHtml = code ? md.render(code) : '';
 | |
|     const cnHtml = cn ? md.render(cn) : '';
 | |
|     let newContent = `
 | |
|       <template>
 | |
|         <demo-box :jsfiddle="${jsfiddle}">
 | |
|           <template slot="component">${template}</template>
 | |
|           <template slot="description">${cnHtml}</template>
 | |
|           <template slot="us-description">${us ? md.render(us) : ''}</template>
 | |
|           <template slot="code">${codeHtml}</template>
 | |
|         </demo-box>
 | |
|       </template>`;
 | |
|     newContent += script
 | |
|       ? `
 | |
|       <script>
 | |
|       ${script || ''}
 | |
|       </script>
 | |
|       `
 | |
|       : '';
 | |
|     newContent += style ? `<style>${style || ''}</style>` : '';
 | |
|     newContent += scopedStyle ? `<style scoped>${scopedStyle || ''}</style>` : '';
 | |
|     const t = new Token('html_block', '', 0);
 | |
|     t.content = newContent;
 | |
|     tokens.push(t);
 | |
|   }
 | |
| });
 | |
| const vueLoaderOptions = {
 | |
|   loaders: {
 | |
|     js: [
 | |
|       {
 | |
|         loader: 'babel-loader',
 | |
|         options: {
 | |
|           presets: ['env'],
 | |
|           plugins: ['transform-vue-jsx', 'transform-object-rest-spread'],
 | |
|         },
 | |
|       },
 | |
|     ],
 | |
|   },
 | |
| };
 | |
| module.exports = {
 | |
|   mode: 'production',
 | |
|   entry: {
 | |
|     index: [`./site/${process.env.ENTRY_INDEX || 'index'}.js`],
 | |
|   },
 | |
|   module: {
 | |
|     rules: [
 | |
|       {
 | |
|         test: /\.md$/,
 | |
|         use: [
 | |
|           {
 | |
|             loader: 'vue-loader',
 | |
|             options: vueLoaderOptions,
 | |
|           },
 | |
|           {
 | |
|             loader: 'vue-antd-md-loader',
 | |
|             options: Object.assign(md, {
 | |
|               wrapper: 'div',
 | |
|               raw: true,
 | |
|             }),
 | |
|           },
 | |
|         ],
 | |
|       },
 | |
|       {
 | |
|         test: /\.vue$/,
 | |
|         loader: 'vue-loader',
 | |
|         options: vueLoaderOptions,
 | |
|       },
 | |
|       {
 | |
|         test: /\.(js|jsx)$/,
 | |
|         loader: 'babel-loader',
 | |
|         exclude: /node_modules/,
 | |
|         options: babelConfig,
 | |
|       },
 | |
|       {
 | |
|         test: /\.(png|jpg|gif|svg)$/,
 | |
|         loader: 'file-loader',
 | |
|         options: {
 | |
|           name: '[name].[ext]?[hash]',
 | |
|         },
 | |
|       },
 | |
|     ],
 | |
|   },
 | |
|   resolve: {
 | |
|     modules: ['node_modules', path.join(__dirname, '../node_modules')],
 | |
|     extensions: ['.js', '.jsx', '.vue', '.md'],
 | |
|     alias: {
 | |
|       vue$: 'vue/dist/vue.esm.js',
 | |
|       antd: path.join(__dirname, 'components'),
 | |
|       'ant-design-vue': path.join(__dirname, 'components'),
 | |
|       'ant-design-vue/es': path.join(__dirname, 'components'),
 | |
|       'ant-design-vue/lib': path.join(__dirname, 'components'),
 | |
|       '@': path.join(__dirname, ''),
 | |
|     },
 | |
|   },
 | |
|   plugins: [new VueLoaderPlugin(), new WebpackBar()],
 | |
| };
 |