赞
踩
把用markdown写的文档拼接成vue文件(这个通过他们自己写的md-loader处理),这个vue文件和我们平时开发项目的vue组件类型(类似<template>...</template><script>export default{}</script>
),再通过vue-loader处理。
首先我们查看ElementUI的package.json文件中的scripts传送门
- "scripts": {
- "dev": "... webpack-dev-server --config build/webpack.demo.js ...",
- }
- 复制代码
通过上图的标注,我们可以知道ElementUI的文档生成的webpack在build/webpack.demo.js里面,webpack.demo.js可以看到webpack是如何处理md文件的,md后缀的文件先通过md-loader处理后,在通过vue-loader处理 webpack.demo.js传送门
- // ...
- {
- test: /\.md$/,
- use: [
- {
- loader: 'vue-loader',
- options: {
- compilerOptions: {
- preserveWhitespace: false
- }
- }
- },
- {
- loader: path.resolve(__dirname, './md-loader/index.js')
- }
- ]
- },
- // ...
- 复制代码

首先找到md-loader的入口文件index.js传送门, 里面的关键代码如下:
- const {
- stripScript, // 提取script
- stripTemplate, // 提取template
- genInlineComponentText // 生成行内组件代码
- } = require('./util');
- const md = require('./config'); // markdown编译器, 下面的 ‘markdown文件如何解析与vue demo代码标记’详细讲解
- module.exports = function(source) {
- const content = md.render(source); // 经过md编译好的代码
- // content里面vue在线栗子的代码被 <!--element-demo: ...vue code... :element-demo-->
- // ...
- // 循环提取出<!--element-demo: ...vue code... :element-demo-->里的 vue code
- while(...){
- var commentContent = content.slice(commentStart + startTagLen, commentEnd); // vue code
- const html = stripTemplate(commentContent); // 提取html
- const script = stripScript(commentContent); // 提取js
- let demoComponentContent = genInlineComponentText(html, script); // 把html, 和js组成组件代码.
- const demoComponentName = `element-demo${id}`; // demo组件名
- output.push(`<template slot="source"><${demoComponentName} /></template>`); // 插入组件
- componenetsString += `${JSON.stringify(demoComponentName)}: ${demoComponentContent},`; // 追加组件字符串
- }
- if (componenetsString) { // 这是script字符串
- pageScript = `<script>
- export default {
- name: 'component-doc',
- components: {
- ${componenetsString}
- }
- }
- </script>`;
- }
- return `
- <template>
- <section class="content element-doc">
- ${output.join('')} // 这是md转的html
- </section>
- </template>
- ${pageScript}
- `;
- };
-
- 复制代码

首先找到上述代码const md = require('./config');
中的文件传送门, 看这个文件的内容再结合package.json里面的依赖,我们可以得知markdown的解析依赖这些开发包markdown-it
(markdown解析器), markdown-it-anchor
(锚点插件,用于段落跳转), markdown-it-chain
(用于链式调用,参考webpack-chain) , markdown-it-container
(自定义包裹元素插件识别remarkdown 语法:::
)
- const Config = require('markdown-it-chain');
- const containers = require('./containers'); // 里面使用markdown-it-container把语法为:::info => <!--element-demo: ...vue code... :element-demo-->
- // ...
- const config = new Config();
- // ... 一些配置, 配置container/anchor
- const md = config.toMd();
-
- module.exports = md;
- 复制代码
- // ...
- render(tokens, idx) {
- const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/); // elementUI文档里面,vue demo都是用:::demo vue code :::包裹着
- if (tokens[idx].nesting === 1) { // 匹配到 :::demo xxxx 替换成return 的字符串
- const description = m && m.length > 1 ? m[1] : '';
- const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''; // content是vue code代码
- return `<demo-block>
- ${description ? `<div>${md.render(description)}</div>` : ''}
- <!--element-demo: ${content}:element-demo-->
- `;
- }
- return '</demo-block>'; // 匹配到 :::, 替换成return 的字符串
- }
- // ...
- 复制代码
通过上述的代码功能主要为 把 :::demo xxxx code :::
转换成 <demo-block> xxx <!--element-demo: code(源码) :element-demo--> code(转义后的代码) </demo-block>
我看md-loader的入口文件index.js传送门里有这么一段代码, let demoComponentContent = genInlineComponentText(html, script);
, 这段代码的功能就是生成demo component字符串, 我们可以跳转到util.js看到如下内容:
- function genInlineComponentText(template, script) {
- // ...
- const compiled = compileTemplate(finalOptions);
- // ...
- let demoComponentContent = `
- ${compiled.code}
- `; // 模板代码 转成vue使用$createElement生成html的render函数
- // ...
- demoComponentContent = `(function() {
- ${demoComponentContent}
- ${script}
- return {
- render,
- staticRenderFns,
- ...democomponentExport
- }
- })()`;
- return demoComponentContent; // 返回字符串
- }
-
- 复制代码

上面的代码主要使用了@vue/component-compiler-utils
vue-template-compiler
来编译template模板,把template模板转成render函数创建dom语法, 然后拼接demo component字符串。
结合markdown文件如何解析与vue demo代码标记和vue demo component是如何生成的这两段的内容再重新看一遍md-loader的入口文件index.js传送门可以发现程序的流程为:markdown
=> html
=> 提取( <!--element-demo: code(源码) :element-demo-->)中的vue代码
=> 编译里面的vue代码,返回demoComponentContent字符串
=> 把html代码与demoComponentContent拼接起来组成新的vue代码。
- // 第一步
- const content = md.render(source); // 经过md编译好的代码, 对应markdown文件如何解析与vue demo代码标记
- // 第二步
- while(...){ // 对应 vue demo component是如何生成的
- // ...
- let demoComponentContent = genInlineComponentText(html, script); // 把html, 和js组成组件代码.
- // ...
- }
- // 第三步
- // ....
- return `
- <template>
- <section class="content element-doc">
- ${output.join('')} // 这是md转的html
- </section>
- </template>
- ${pageScript}
- `;

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。