preface

I have been learning the basics of WebPack for a while, but neither the documentation nor the introductory video is as good as what I learned in practice.

Here are a few things I learned while working on the MarkDown-to-HTML plugin (sort of consolidating my webPack primer). (B station front end of The video of Ono Mori, you can check it out if you are interested) including but not limited to:

  • Some basic configuration of WebPack
  • Some regular expression writing
  • How do I build a DOM tree
  • .

The result is this: The Markdowm on the left renders as the HTML on the right

Instead of thinking about how to get Markdown to HTML, let’s look at how to get started. Let’s release the directory:

  1. First, you need to build a project with WebPack.
  2. Create a plugin folder that contains the soul of our plugin
  3. Since it is MD to HTML then we have a MD document, MY MD document should be transferred to imaging first<h1>**</h1>A similar string containing the contents is inserted into the template.html template to output an HTML file

1. Building projects with WebPack (in Retrospect)

  1. Create a folder for md-to-html-plugin

Use the following command

  • npm init -y
  • npm install webpack webpack-cli webpack-dev-server -D

Create it in the root directory

  • webpack.config.js
  • src/app.js
  • plugin/md-to-html-plugin/ index.js
  • plugin/md-to-html-plugin/ compier.js

<h1>**</h1> </h1>

  • plugin/md-to-html-plugin/template.html

The following are introduced in turn:

2. Webpack. Config. Js configuration

Contains:

  • Packing entry
  • Export output
  • Pattern mode
  • Plugin MdToHtmlPlugin (our own)
const { resolve } = require('path')
const MdToHtmlPlugin = require('./plugin/md-to-html-plugin')

module.exports = {
    mode: 'development'.entry: resolve(__dirname, 'src/app.js'),
    output: {
        path: resolve(__dirname, 'dist'),
        filename:'app.js'
    },
    plugins: [
        new MdToHtmlPlugin({
            template: resolve(__dirname, 'text.md'),
            filename: 'text.html']}}),Copy the code

3. Md-to-html-plugin/index.js

3.1 Definition of plug-in:

Plug-ins are instantiated from a constructor on which the Prototype object has the apply method. This apply method is called by the WebPack Compiler once when the plug-in is installed. The apply method can receive a reference to the WebPack Compiler object, which can be accessed in a callback function.

3.2 MdToHtmlPlugin infrastructure

const { readFileSync } = require('fs') 1.You need to read the file MD and the templateconst { resolve } = require('path') 
const INNER_MARK = '<! -- inner -->' 2.Template.html to hold the transformed HTML tagsconst {compileHTML} = require('./compiler') 3.Md - HTML conversionclass MdToHtmlPlugin { 4.In the WebPack configuration we use thenewThe way to create this side, we set up aclassClass, which takes two arguments,mdThe filename of the document, and the filename of the outputconstructor({ template, filename }) {
    5.If the MD file cannot be found, the error is directly guaranteedif(! template) {throw new Error('Template not found')}this.template = template
    6.Set the output file name, if there is a file name, if not, set to'md.html'
        this.filename = filename ? filename : 'md.html'
    }
    7.The apply () methodapply(compiler) {
        compiler.hooks.emit.tap('md-to-html-plugin'.(compilation) = > {
        // I put the whole apply method content below to analyze
           8.In this method, we will read the md document, generate a DOM tree, and put it back in template-html})}}module.exports =  MdToHtmlPlugin
Copy the code

3.3 the apply () method

  1. compiler
  • compiler.hooks.emit.tap
  • Emit: Generate resources before the output directory
  • Parameters:compilation
  1. compilation
 apply(compiler) { 
        compiler.hooks.emit.tap('md-to-html-plugin'.(compilation) = > {
            const _assets = compilation.assets;
            const _mdContent = readFileSync(this.template, 'utf8');
            const _templateHtml = readFileSync(resolve(__dirname, 'template.html'), 'utf8')
            // Convert the md document lines into an array _mdContentArray
            const _mdContentArray = _mdContent.split('\n') 
            // compileHTML constructs this number into a DOM tree _htmlStr
            const _htmlStr = compileHTML(_mdContentArray)
            // Insert the DOM into template.html
            const _finalHTML = _templateHtml.replace(INNER_MARK,_htmlStr)
            _assets[this.filename] = {
                source() {
                    return _finalHTML
                },
                size() {
                    return _finalHTML.length
                }
            }
           
        })
    }
Copy the code

Website:

A plug-in consists of the following

  • A named JavaScript function.MdToHtmlPlugin
  • Define it on its prototypeapplyMethods.apply(compiler)
  • Specify one that touches the WebPack itselfEvent hooks.compiler.hooks.emit.tap
  • Manipulate instance-specific data within WebPack.
  • The Callback provided by WebPack is called after the functionality is implemented

4. Md-to-html string conversion

4.1 Using JS Objects to create trees

4.1.1 What tree to create:

{
    'h1-1626856207419': { type: 'single'.tags: [ '

This is an h1 title \r

'
]},'ul-1626856207993': { type: 'wrap'.tags: [ '
  • the first item in this ul list \r
  • '
    .'
  • the first item in this ul list \r
  • '
    .'
  • the first item in this ul list \r
  • '
    .'
  • the first item in this ul list \r
  • '
    ]},'h2-1626856207560': { type: 'single'.tag: [ '

    This is an h2 title \r

    '
    ]},'ol-1626856207336': { type: 'wrap'.tags: [ '
  • . This is the first item in an ol list \r
  • '
    .'
  • . This is the first item in an ol list \r
  • '
    .'
  • . This is the first item in an ol list \r
  • '
    .'
  • . This is the first item in an ol list
  • '
    ]}}Copy the code

    4.1.2 Detailed Steps:

    First of all, we passed an array of rows to compileHTML(_mdContentArray) in index.js, hoping that compileHTML would first convert the md array to a DOM tree. Insert the tree into the template.

    • Convert the MD array to a DOM tree

    There are three kinds of things

    1. # # #The title class we need to convert to h1 and H2
    2. -Unordered list we need to convert to UL li
    3. 1. 2.Ordered list we need to convert to Ol Li

    Of course, each tag contains the content we need. input = matched.input

    • Use the re to distinguish the cases in this set
    const reg_mark = / ^ (. +?) \s/
    // Match the beginning of #
    const reg_sharp = / # ^ \ /
    // Match an unordered list -
    const reg_crossbar = / ^ \ - /
    // Match ordered list 1. 2.
    const reg_number = /^\d/
    Copy the code
    • One more thing to note

    The Li in UL and the Li in OL are put into UL or OL together, so it is necessary to judge whether the opening label of the last time is the same as that of this time

    _lastMark === mark
    Copy the code

    4.1.3 Specific code:

    function createTreel(_mdArr) {
        let _htmlPool = {}
        let _lastMark = ' ' // This is used to determine whether, like the li label, it needs to be put together in ol or ul
        let _key = 0
    
            _mdArr.forEach(mdFragment= > {
                // console.log(mdFragment)
                const matched = mdFragment.match(reg_mark);
                if (matched) {
                    const mark = matched[1]
                    const input = matched.input
                    console.log(matched,'matched') // We can see what is printed by matched here
                    // md-to-html three operations title unordered list ordered list}});return _htmlPool
       
    }
    Copy the code

    Here’s what Matched printed out

    const mark = matched[1] md matches ## # -1.Etc.constInput = matched. Input contentCopy the code
    [ The '#'.The '#'.index: 0.input: '# This is a h1 title \r'.groups: undefined ] matched
    [ The '-'.The '-'.index: 0.input: '- the first item in this ul list \r'.groups: undefined ] matched
    [ The '-'.The '-'.index: 0.input: '- the first item in this ul list \r'.groups: undefined ] matched
    [ The '-'.The '-'.index: 0.input: '- the first item in this ul list \r'.groups: undefined ] matched
    [ The '-'.The '-'.index: 0.input: '- the first item in this ul list \r'.groups: undefined ] matched
    [ '## '.'# #'.index: 0.input: '## this is a h2 title \r'.groups: undefined ] matched
    ['1..'1..index: 0.input: '1. The first item of this ol list \r'.groups: undefined] matched
    ['2.'.'2.'.index: 0.input: '2. The first item of this ol list \r'.groups: undefined] matched
    ['3.'.'3.'.index: 0.input: '3. The first item of this ol list \r'.groups: undefined] matched
    [ '4..'4..index: 0.input: '4. This is the first item in an OL list '.groups: undefined ] matched
    Copy the code

    4.3 Detailed processing of mD-to-HTML strings

    4.3.1 Processing the Unique Value of key

    function randomNum() {
        return new Date().getTime() + parseInt(Math.random() * 1000);
    }
    
    module.exports = {
        randomNum
    }
    Copy the code

    4.3.2 Processing of headings H1 h2

    1. First match the title h1.h2…
    if (reg_sharp.test(mark)) { // Match #
          const tag = `h${mark.length}`; // Convert to h1, H2, etc
          const tagContent = input.replace(reg_mark, ' ')
         if (_lastMark === mark) {
         // If the previous tag is the same as this one, splice it before
             _htmlPool[`${tag}-${_key}`].tags = [..._htmlPool[`${tag}-${_key}`].tags,` <${tag}>${tagContent}</${tag}> `]}else {
         // Otherwise create a new title tag
             _lastMark = mark
              _key = randomNum();
              _htmlPool[`${tag}-${_key}`] = {
                  type: 'single'.// A single identifier
                   tags: [` <${tag}>${tagContent}</${tag}> `]}}}Copy the code

    4.3.3 Processing unordered Lists

     if (reg_crossbar.test(mark)) {
         // console.log(matched)
           const tagContent = input.replace(reg_mark, ' ');
           const tag = 'li';
    
           if (reg_crossbar.test(_lastMark)) {
               _htmlPool[`ul-${_key}`].tags = [..._htmlPool[`ul-${_key}`].tags ,` <${tag}>${tagContent}</${tag}> `]}else {
                _lastMark = mark
                _key = randomNum();
                 _htmlPool[`ul-${_key}`] = {
                type: 'wrap'.// Multiple identifiers
                tags: [` <${tag}>${tagContent}</${tag}> `]}}}Copy the code

    4.3.4 Processing ordered lists

    if (reg_number.test(mark)) {
        const tagContent = input.replace(reg_number, ' ')
        const tag = 'li'
    
        if (reg_number.test(_lastMark)) {
           _htmlPool[`ol-${_key}`].tags = [..._htmlPool[`ol-${_key}`].tags ,` <${tag}>${tagContent}</${tag}> `]}else {
               _lastMark = mark;
               _key = randomNum();
    
                _htmlPool[`ol-${_key}`] = {
                    type: 'wrap'.tags: [` <${tag}>${tagContent}</${tag}> `]}}}Copy the code

    4.4 Template Compilation

    function compileHTML(_mdContentArray) {
        const _htmlPool = createTreel(_mdContentArray)
        // sconsole.log(_htmlPool)
        let _htmlStr = ' '
        let item
    
        for (let k in _htmlPool) {
            // console.log(k, _htmlPool[k])
            item = _htmlPool[k]
            if (item.type === 'single') {
            // A single title tag
                item.tags.forEach((tag) = >{ _htmlStr += tag; })}else if (item.type === 'wrap') {
            // Multiple tag lists
                console.log(item.tags,'2')
                let _list = ` <${k.split(The '-') [0]}> `
    
                item.tags.forEach((tag) = > {
                    _list += tag;
                })
    
                _list += ` < /${k.split(The '-') [0]}> `
                _htmlStr += _list
            }
        }
        return _htmlStr
        
    }
    
    module.exports = {
        compileHTML
    }
    Copy the code

    5. Compile the template

    There’s a comment in the body

    <! DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta Name ="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <body> <! -- inner --> </body> </html>Copy the code

    Reference documents:

    1. The webpack compiler hook

    2. Video

    There are many places will not not understand, continue to learn…