background

Our company has a self-maintained application component library, but the application component library is not documented. at the same time, it can not run online.

The overall idea of the ElementUI document

Splicing documents written in Markdown into vUE files (this is handled by the MD-Loader they wrote themselves) that match the vUE component type of our normal development projects (like
), then use vue-loader to process.

How webPack is configured (v2.13.2)

First we look at the scripts portal in ElementUI’s package.json file

"scripts": {

 "dev""... webpack-dev-server --config build/webpack.demo.js ...".

}

Copy the code

From the annotation above, we can see that the webpack generated by ElementUI’s document is in build/webpack.demo.js. Webpack.demo.js can see how webpack handles md files. Files with the md suffix are processed by mD-loader first, and then the webpack.demo.js portal is processed by vue-loader

// ...

      {

        test/\.md$/.

        use: [

          {

            loader'vue-loader'.

            options: {

              compilerOptions: {

                preserveWhitespacefalse

              }

            }

          },

          {

            loader: path.resolve(__dirname, './md-loader/index.js')

          }

        ]

      },

/ /...

Copy the code

How mD-Loader works (V2.13.2)

Md-loader import file index.js portal, which contains the following key code:

const {

  stripScript, / / script

  stripTemplate, / / to extract the template

  genInlineComponentText // Generate inline component code

} = require('./util');

const md = require('./config'); // Markdown compiler, how to parse markdown files with vue demo code markup

module.exports = function(source{

  const content = md.render(source); // MD-compiled code

   // The vue online chestnut code is <! --element-demo: ... vue code... :element-demo-->

  // ...

  // loop out <! --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); // Combine HTML and JS into component code.

    const demoComponentName = `element-demo${id}`// Demo component name

    output.push(`<template slot="source"><${demoComponentName} /></template>`); // Insert the component

    componenetsString += `The ${JSON.stringify(demoComponentName)}${demoComponentContent}, `// Appends the component string

  }

  if (componenetsString) { // This is a script string

    pageScript = `<script>

      export default {

        name: 'component-doc',

        components: {

          ${componenetsString}

        }

      }

    </script>`
;

  }

  return `

    <template>

      <section class="content element-doc">

        ${output.join(' ')}// This is the HTML from md

      </section>

    </template>

    ${pageScript}

  `
;

};



Copy the code

How do Markdown files parse with Vue Demo code tags

Const md = require(‘./config’); Look at the contents of this file combined with dependencies in package.json, We can see that markdown parsing relies on these development packages markdown-it(Markdown parser), Markdown-it-Anchor (anchor plug-in for paragraph jump), Markdown-it-chain (used in chain calls, refer to webpack-chain), Markdown-it-container (Custom wrap elements plug-in identified the remarkdown syntax ::)

config.js

const Config = require('markdown-it-chain');

const containers = require('./containers'); // Use markdown-it-container to set the syntax to :::info => <! --element-demo: ... vue code... :element-demo-->

// ...

const config = new Config();

/ /... Some configurations, configure container/ Anchor

const md = config.toMd();



module.exports = md;

Copy the code

containers.js

// ...

    render(tokens, idx) {

      const m = tokens[idx].info.trim().match(/^demo\s*(.*)$/); // Within the elementUI document, vue Demo is wrapped with ::: Demo Vue code :::

      if (tokens[idx].nesting === 1) { // Matches :::demo XXXX and replaces it with the string of return

        const description = m && m.length > 1 ? m[1] : ' ';

        const content = tokens[idx + 1].type === 'fence' ? tokens[idx + 1].content : ' '// Content is vue code

        return `<demo-block>

        ${description ? `<div>${md.render(description)}</div>` : ' '}

<! --element-demo:${content}:element-demo-->

        `
;

      }

      return '</demo-block>'// Matches ::: and replaces it with the return string

    }

/ /...

Copy the code


XXX
code(escape code)

How is the Vue Demo Component generated

Let DemoentContent = genInlineComponentText(HTML, script); This code generates the Demo Component string. We can jump to util.js and see the following:



function genInlineComponentText(template, script{

  // ...

  const compiled = compileTemplate(finalOptions);

  // ...

  let demoComponentContent = `

    ${compiled.code}

  `
// The template code is converted to vue using $createElement to generate the HTML render function

  // ...

  demoComponentContent = `(function() {

    ${demoComponentContent}

    ${script}

    return {

      render,

      staticRenderFns,

. democomponentExport

    }

`}) ()
;

  return demoComponentContent; // Returns a string

}



Copy the code

Vue /component-compiler-utils Vue -template-compiler is used to compile the template template, convert the template template into the render function to create dom syntax. Then concatenate the Demo Component string.

conclusion

How to parse the markdown file and how to generate the vue Demo component by using the markdown file and the vue Demo component Markdown => HTML => Extract (
) in the VUE code => compile inside the VUE code, return demoComponentContent string => HTML code and demoComponentContent splice together to form a new VUE code.

/ / the first step

const content = md.render(source); // MD-compiled code, corresponding markdown file how to parse and vue demo code markup

/ / the second step

  while(...). {// How is the corresponding Vue Demo Component generated

      // ...

     let demoComponentContent = genInlineComponentText(html, script); // Combine HTML and JS into component code.

     // ...

  }

  / / the third step

    / /...

    return `

    <template>

      <section class="content element-doc">

        ${output.join(' ')}// This is the HTML from md

      </section>

    </template>

    ${pageScript}

  `
;

Copy the code