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(); }; /** * `{{ }}` => `{{ }}` * @param {string} str * @return {string} */ const replaceDelimiters = function(str) { return str.replace(/({{|}})/g, '$1'); }; /** * 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)(?:[^<]|<)+', 'g'); const usReg = new RegExp('<(us)(?:[^<]|<)+', '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 = ` `; newContent += script ? ` ` : ''; newContent += style ? `` : ''; newContent += scopedStyle ? `` : ''; 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()], };