当前位置:   article > 正文

ElementUI文档是如何实现的_element-ui 说明文档是怎么实现的

element-ui 说明文档是怎么实现的

ElementUI文档的整体思路

把用markdown写的文档拼接成vue文件(这个通过他们自己写的md-loader处理),这个vue文件和我们平时开发项目的vue组件类型(类似<template>...</template><script>export default{}</script>),再通过vue-loader处理。

webpack是如何配置的 (v2.13.2)

首先我们查看ElementUI的package.json文件中的scripts传送门

  1. "scripts": {
  2.  "dev""... webpack-dev-server --config build/webpack.demo.js ...",
  3. }
  4. 复制代码

通过上图的标注,我们可以知道ElementUI的文档生成的webpack在build/webpack.demo.js里面,webpack.demo.js可以看到webpack是如何处理md文件的,md后缀的文件先通过md-loader处理后,在通过vue-loader处理 webpack.demo.js传送门

  1. // ...
  2.       {
  3.         test/\.md$/,
  4.         use: [
  5.           {
  6.             loader'vue-loader',
  7.             options: {
  8.               compilerOptions: {
  9.                 preserveWhitespacefalse
  10.               }
  11.             }
  12.           },
  13.           {
  14.             loader: path.resolve(__dirname, './md-loader/index.js')
  15.           }
  16.         ]
  17.       },
  18. // ...      
  19. 复制代码

md-loader是如何工作的 (v2.13.2)

首先找到md-loader的入口文件index.js传送门, 里面的关键代码如下:

  1. const {
  2.   stripScript, // 提取script
  3.   stripTemplate, // 提取template
  4.   genInlineComponentText // 生成行内组件代码
  5. } = require('./util');
  6. const md = require('./config'); // markdown编译器, 下面的 ‘markdown文件如何解析与vue demo代码标记’详细讲解
  7. module.exports = function(source) {
  8.   const content = md.render(source); // 经过md编译好的代码
  9.    // content里面vue在线栗子的代码被  <!--element-demo: ...vue code... :element-demo-->
  10.   // ...
  11.   // 循环提取出<!--element-demo: ...vue code... :element-demo-->里的 vue code
  12.   while(...){
  13.     var commentContent = content.slice(commentStart + startTagLen, commentEnd); // vue code
  14.     const html = stripTemplate(commentContent); // 提取html
  15.     const script = stripScript(commentContent); // 提取js
  16.      let demoComponentContent = genInlineComponentText(html, script); // 把html, 和js组成组件代码.
  17.     const demoComponentName = `element-demo${id}`// demo组件名
  18.     output.push(`<template slot="source"><${demoComponentName} /></template>`); // 插入组件
  19.     componenetsString += `${JSON.stringify(demoComponentName)}${demoComponentContent},`// 追加组件字符串
  20.   }
  21.   if (componenetsString) { // 这是script字符串
  22.     pageScript = `<script>
  23.       export default {
  24.         name: 'component-doc',
  25.         components: {
  26.           ${componenetsString}
  27.         }
  28.       }
  29.     </script>`;
  30.   }
  31.   return `
  32.     <template>
  33.       <section class="content element-doc">
  34.         ${output.join('')} // 这是md转的html
  35.       </section>
  36.     </template>
  37.     ${pageScript}
  38.   `;
  39. };
  40. 复制代码

markdown文件如何解析与vue demo代码标记

首先找到上述代码const md = require('./config');中的文件传送门, 看这个文件的内容再结合package.json里面的依赖,我们可以得知markdown的解析依赖这些开发包markdown-it(markdown解析器), markdown-it-anchor(锚点插件,用于段落跳转), markdown-it-chain(用于链式调用,参考webpack-chain) , markdown-it-container(自定义包裹元素插件识别remarkdown 语法:::)

config.js

  1. const Config = require('markdown-it-chain');
  2. const containers = require('./containers'); // 里面使用markdown-it-container把语法为:::info =>  <!--element-demo: ...vue code... :element-demo-->
  3. // ...
  4. const config = new Config();
  5. // ... 一些配置, 配置container/anchor
  6. const md = config.toMd();
  7. module.exports = md;
  8. 复制代码

containers.js

  1. // ...
  2.     render(tokens, idx) {
  3.       const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/); // elementUI文档里面,vue demo都是用:::demo vue code :::包裹着
  4.       if (tokens[idx].nesting === 1) { // 匹配到 :::demo xxxx 替换成return 的字符串
  5.         const description = m && m.length > 1 ? m[1] : '';
  6.         const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ''// content是vue code代码
  7.         return `<demo-block>
  8.         ${description ? `<div>${md.render(description)}</div>` : ''}
  9.         <!--element-demo: ${content}:element-demo-->
  10.         `;
  11.       }
  12.       return '</demo-block>'// 匹配到 :::, 替换成return 的字符串
  13.     }
  14. // ...    
  15. 复制代码

通过上述的代码功能主要为 把 :::demo xxxx code ::: 转换成 <demo-block> xxx <!--element-demo: code(源码) :element-demo--> code(转义后的代码) </demo-block>

vue demo component是如何生成的

我看md-loader的入口文件index.js传送门里有这么一段代码, let demoComponentContent = genInlineComponentText(html, script);, 这段代码的功能就是生成demo component字符串, 我们可以跳转到util.js看到如下内容:

  1. function genInlineComponentText(template, script) {
  2.   // ...
  3.   const compiled = compileTemplate(finalOptions);
  4.   // ...
  5.   let demoComponentContent = `
  6.     ${compiled.code}
  7.   `; // 模板代码 转成vue使用$createElement生成html的render函数
  8.   // ...
  9.   demoComponentContent = `(function() {
  10.     ${demoComponentContent}
  11.     ${script}
  12.     return {
  13.       render,
  14.       staticRenderFns,
  15.       ...democomponentExport
  16.     }
  17.   })()`;
  18.   return demoComponentContent; // 返回字符串
  19. }
  20. 复制代码

上面的代码主要使用了@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代码。

  1. // 第一步 
  2. const content = md.render(source); // 经过md编译好的代码, 对应markdown文件如何解析与vue demo代码标记
  3. // 第二步
  4.   while(...){ // 对应 vue demo component是如何生成的
  5.       // ...
  6.      let demoComponentContent = genInlineComponentText(html, script); // 把html, 和js组成组件代码.
  7.      // ...
  8.   }
  9.   // 第三步
  10.     // ....
  11.     return `
  12.     <template>
  13.       <section class="content element-doc">
  14.         ${output.join('')} // 这是md转的html
  15.       </section>
  16.     </template>
  17.     ${pageScript}
  18.   `;
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小舞很执着/article/detail/744476
推荐阅读
相关标签
  

闽ICP备14008679号