задний план
В нашей компании есть самостоятельная библиотека компонентов приложения, но документации библиотеки компонентов приложения недостаточно, и в то же время мы не можем запускать каштаны онлайн.После прочтения документации 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
(Плагин пользовательского элемента обтекания распознает синтаксис замечаний:::
)
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>
Как генерируется демонстрационный компонент 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}
`;