Как реализована документация ElementUI

Element

задний план

В нашей компании есть самостоятельная библиотека компонентов приложения, но документации библиотеки компонентов приложения недостаточно, и в то же время мы не можем запускать каштаны онлайн.После прочтения документации ElementUI, это неплохо. ) План внедрения ElementUI для написания внутренней документации описания компонентов компании.

Общая идея документации ElementUI

Объединение документов, написанных в уценке, в файлы vue (это обрабатывается их собственным md-загрузчиком), этот файл vue совпадает с типом компонента vue нашего обычного проекта разработки (аналогично<template>...</template><script>export default{}</script>), а затем обрабатывается vue-loader.

Как настроен веб-пакет (v2.13.2)

Сначала мы рассмотрим сценарии в файле package.json ElementUI.портал

"scripts": {
 "dev": "... webpack-dev-server --config build/webpack.demo.js ...",
}

Из аннотаций на приведенном выше рисунке мы можем узнать, что веб-пакет, сгенерированный документом ElementUI, находится в build/webpack.demo.js, а webpack.demo.js может видеть, как веб-пакет обрабатывает файлы 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 (v2.13.2)

Сначала найдите файл index.js md-loader.портал, код ключа внутри выглядит следующим образом:

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}
  `;
};

Как анализировать файлы уценки с тегами демо-кода vue

Сначала найдите приведенный выше кодconst md = require('./config');файлы впортал, Глядя на содержимое этого файла в сочетании с зависимостями в package.json, мы можем знать, что синтаксический анализ уценки зависит от этих пакетов разработки.markdown-it(парсер уценки),markdown-it-anchor(якорный плагин для перехода по абзацам),markdown-it-chain(для связанных вызовов обратитесь к цепочке webpack),markdown-it-container(Плагин пользовательского элемента обтекания распознает синтаксис замечаний:::)

config.js

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;

containers.js

// ...
    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>

Как генерируется демонстрационный компонент vue

Я смотрю на входной файл index.js md-loaderпорталЕсть такой кусок кода,let demoComponentContent = genInlineComponentText(html, script);, Функция этого кода состоит в том, чтобы сгенерировать строку демонстрационного компонента, мы можем перейти к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Чтобы скомпилировать шаблон шаблона, преобразуйте шаблон шаблона в функцию рендеринга, чтобы создать синтаксис dom, а затем соедините строку демо-компонента.

Суммировать

комбинироватьКак анализировать файлы уценки с тегами демо-кода vueа такжеКак генерируется демонстрационный компонент vueПеречитайте содержимое этих двух абзацев, входной файл index.js md-loader.порталМожно обнаружить, что процесс программы: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}
  `;