1 Star 1 Fork 0

高腾骏/md-to-html-plugin

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
该仓库未声明开源许可证文件(LICENSE),使用请关注具体项目描述及其代码上游依赖。
克隆/下载
贡献代码
同步代码
取消
提示: 由于 Git 不支持空文件夾,创建文件夹后会生成空的 .keep 文件
Loading...
README
ISC

1. 项目初始化

{
  "name": "md-to-html-plugin",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^4.30.0",
    "webpack-cli": "^3.3.0",
    "webpack-dev-server": "^3.7.2"
  }
}

2. webpack配置文件

  • 使用自定义plugin
  • 解析根目录下的test.md文件
  • 在打包完后生成test.html文件,并替换模板中的注释
const { resolve } = require('path');
const MdToHtmlPlugin = require('./plugins/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, './test.md'), // 要转换的markdown文件
            filename: 'test.html',
        })
    ]
}

3. 插件目录

image.png

1. utils.js

  • 随机数生成函数
function randomNum() {
  return new Date().getTime() + parseInt(Math.random() * 10000);
}

module.exports = {
  randomNum
}

2. template.html

  • 解析markdown文件转换为html字符串
  • 替换<!-- inner -->
<!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>
  </head>
  <body>
    <!-- inner -->
  </body>
</html>

3. compiler.js

  • 创建树形结构方法
  • 拼接html字符串
const { randomNum } = require('./utils');

const reg_mark = /^(.+?)\s/; // 以空字符串开头  以空格结尾
const reg_sharp = /^\#/; // 以#号开头
const reg_crossbar = /^\-/; // 以-开头
const reg_number = /^\d/; // 以数字开头的

// 创建树形结构
function createTree(mdArr) {
    let _htmlPool = {};
    let _lastMark = '';
    let _key = 0;

    mdArr.forEach((mdFragment) => {
        const matched = mdFragment.match(reg_mark);
         
        // 因为存在null,所以真才处理
        if(matched) {
            const mark = matched[1],
                  input = matched['input'];

            // 以#号开头
            if(reg_sharp.test(mark)) {
                // 有几个#号就是h几
                const tag = `h${mark.length}`;
                // 获取内容
                const tagContent = input.replace(reg_mark, '');
 
                if(_lastMark == mark) {
                    _htmlPool[`${tag}-${_key}`].tags = [..._htmlPool[`${tag}-${_key}`].tags, `<${tag}>${tagContent}</${tag}>`]
                } else {
                    _lastMark = mark;
                    _key = randomNum();
                    _htmlPool[`${tag}-${_key}`] = {
                        type: 'single',
                        tags: [`<${tag}>${tagContent}</${tag}>`]
                    }
                }
            }

            // 以-开头
            if(reg_crossbar.test(mark)) {
                const tagContent = input.replace(reg_mark, '');
                
                const tag = `li`;

                // 判断当前上一次的mark是否匹配正则
                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',
                        tags: [`<${tag}>${tagContent}</${tag}>`]
                    }
                }
            }

            // 以数字开头
            if(reg_number.test(mark)) {
                 
                // 替换掉前面的内容 以空字符串开头中间至少有一位,以空格结尾的匹配出来,替换成空 
                const tagContent = input.replace(reg_mark, '');
                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}>`]
                    }
                }
            }
        }
    });

    return _htmlPool;
}


function compileHTML(_mdArr) {
    const _htmlPool = createTree(_mdArr);
    let _htmlStr = '';
    let item;
    // console.log(_htmlPool);
    for(var k in _htmlPool) {
        // console.log(k, _htmlPool[k]);
        item = _htmlPool[k];
        // console.log(item);
        if(item.type === 'single') {
            // 遍历拼接type 为single的html字符串

            item.tags.map(tag => {
                console.log(tag);
                _htmlStr += tag;
            })
        } 
        else if(item.type === 'wrap') {
            let _list = `<${k.split('-')[0]}>`;

            item.tags.forEach(tag => {
                _list += tag;
            });

            _list += `</${k.split('-')[0]}>`;

            _htmlStr += _list;
        }
    }

    // console.log(_htmlStr);
    return _htmlStr;
}

module.exports = {
    compileHTML
}

/**
 * {
 *   h1: {
 *      type: 'single',
 *      tags: [<h1>这是一个h1的标题</h1>]
 *   },
 *   ul: {
 *      type: 'wrap'
 *      tags: [
 *        '<li>这是UL列表的第1项</li>',
 *        '<li>这是UL列表的第1项</li>',
 *        '<li>这是UL列表的第1项</li>',
 *        '<li>这是UL列表的第1项</li>',
 *      ]
 *   }
 * }
 */

4. index.js

  • 主要插件代码
  • 插件一般都是new使用
  • 所以是一个类
  1. 用户需要传入两个参数
    1. 要解析的markdown文件路径
    2. 打包后生成的html文件名
  2. 用户没有指定编译模板需要抛出错误,默认生成文件名md.html
  3. webpack为每个plugins插件提供了一个方法apply并传入一个编译器参数
    1. 编译器下边有一个hooks在下边存在emit中有个一tap方法
      1. 第一个参数插件名
      2. 第二个汇编结果
  4. 默认打包后的汇编文件只有一个app.js

image.png

  1. 获取markdown文件内容
  2. 获取当前模板文件内容
  3. 将markdown文件中的内容按照一行一行存储到数组中
  4. 调用编译方法将markdown字符编译成html字符串
    1. 需要先将数组数据转换成树形结构数据
      1. 利用正则匹配出每种markdown语法类型
      2. 为每种语法对应每种html标签
      3. 相同的markdown为同一分组下的
      4. 还需要使用随机数,区分相同的标签
    2. 遍历数据,按照树中type的不同拼接html字符串
    3. 最后将拼接完成的html字符串返回
  5. 将html文件中的注释替换成markdown转换后的html字符串
  6. 在汇编文件上添加用户配置的文件名
    1. 打包后会生成新文件
const { readFileSync } = require('fs');
const { resolve } = require('path');
const { compileHTML } = require('./compiler');

const INNER_MARK = '<!-- inner -->';

class MdToHtmlPlugin {
    constructor({ template, filename }) {

        // 用户没有传入模板 抛出错误
        if(!template) {
            throw new Error('The config for "template" must be configured');
        }

        this.template = template;
        this.filename = filename ? filename : 'md.html';
    }

    // webpack为每个插件提供一个方法apply
    // 编译的过程中都是在apply中做的
    // 有一个参数编译器 compiler

    apply(compiler) {
        // 编译器 下的hooks 下有个发射器
        compiler.hooks.emit.tap('md-to-html-plugin', (compilation) => {
            const _assets = compilation.assets;
            // 读取用户webpack中配置的模板文件
            const _mdContent = readFileSync(this.template, 'utf8');
            // 读取模板html
            const _templateHTML = readFileSync(resolve(__dirname, 'template.html'), 'utf8')
            // 将md文件一行一行的存储到数组中
            const _mdContentArr = _mdContent.split('\n');
       
            // 编译md字符串为html字符串
            const _htmlStr = compileHTML(_mdContentArr);

            console.log(_htmlStr);
            // 将注释替换成md字符串转换成的html字符串
            const _finalHTML = _templateHTML.replace(INNER_MARK, _htmlStr); 

            // 在_assets上增加资源
            _assets[this.filename] = {
                source() { // 方法返回一个资源
                    return _finalHTML; 
                },
                size() { // 一般return 资源的长度
                    return _finalHTML.length;
                }
            }

            // console.log(_assets);
        })
    }
}


module.exports = MdToHtmlPlugin;
## 1. 项目初始化 ```json { "name": "md-to-html-plugin", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "build": "webpack" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.30.0", "webpack-cli": "^3.3.0", "webpack-dev-server": "^3.7.2" } } ``` ## 2. webpack配置文件 - 使用自定义plugin - 解析根目录下的test.md文件 - 在打包完后生成test.html文件,并替换模板中的注释 ```json const { resolve } = require('path'); const MdToHtmlPlugin = require('./plugins/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, './test.md'), // 要转换的markdown文件 filename: 'test.html', }) ] } ``` ## 3. 插件目录 ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22065308/1651045385975-7d2c375a-b6a5-458e-85c1-bbc81e627fac.png#clientId=ud5ccf0d2-a961-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=471&id=u069e5593&margin=%5Bobject%20Object%5D&name=image.png&originHeight=471&originWidth=908&originalType=binary&ratio=1&rotation=0&showTitle=false&size=31457&status=done&style=none&taskId=u4e1a8551-8c5b-4119-b59f-69cdf703604&title=&width=908) ### 1. utils.js - 随机数生成函数 ```javascript function randomNum() { return new Date().getTime() + parseInt(Math.random() * 10000); } module.exports = { randomNum } ``` ### 2. template.html - 解析markdown文件转换为html字符串 - 替换`<!-- inner -->` ```html <!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> </head> <body> <!-- inner --> </body> </html> ``` ### 3. compiler.js - 创建树形结构方法 - 拼接html字符串 ```javascript const { randomNum } = require('./utils'); const reg_mark = /^(.+?)\s/; // 以空字符串开头 以空格结尾 const reg_sharp = /^\#/; // 以#号开头 const reg_crossbar = /^\-/; // 以-开头 const reg_number = /^\d/; // 以数字开头的 // 创建树形结构 function createTree(mdArr) { let _htmlPool = {}; let _lastMark = ''; let _key = 0; mdArr.forEach((mdFragment) => { const matched = mdFragment.match(reg_mark); // 因为存在null,所以真才处理 if(matched) { const mark = matched[1], input = matched['input']; // 以#号开头 if(reg_sharp.test(mark)) { // 有几个#号就是h几 const tag = `h${mark.length}`; // 获取内容 const tagContent = input.replace(reg_mark, ''); if(_lastMark == mark) { _htmlPool[`${tag}-${_key}`].tags = [..._htmlPool[`${tag}-${_key}`].tags, `<${tag}>${tagContent}</${tag}>`] } else { _lastMark = mark; _key = randomNum(); _htmlPool[`${tag}-${_key}`] = { type: 'single', tags: [`<${tag}>${tagContent}</${tag}>`] } } } // 以-开头 if(reg_crossbar.test(mark)) { const tagContent = input.replace(reg_mark, ''); const tag = `li`; // 判断当前上一次的mark是否匹配正则 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', tags: [`<${tag}>${tagContent}</${tag}>`] } } } // 以数字开头 if(reg_number.test(mark)) { // 替换掉前面的内容 以空字符串开头中间至少有一位,以空格结尾的匹配出来,替换成空 const tagContent = input.replace(reg_mark, ''); 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}>`] } } } } }); return _htmlPool; } function compileHTML(_mdArr) { const _htmlPool = createTree(_mdArr); let _htmlStr = ''; let item; // console.log(_htmlPool); for(var k in _htmlPool) { // console.log(k, _htmlPool[k]); item = _htmlPool[k]; // console.log(item); if(item.type === 'single') { // 遍历拼接type 为single的html字符串 item.tags.map(tag => { console.log(tag); _htmlStr += tag; }) } else if(item.type === 'wrap') { let _list = `<${k.split('-')[0]}>`; item.tags.forEach(tag => { _list += tag; }); _list += `</${k.split('-')[0]}>`; _htmlStr += _list; } } // console.log(_htmlStr); return _htmlStr; } module.exports = { compileHTML } /** * { * h1: { * type: 'single', * tags: [<h1>这是一个h1的标题</h1>] * }, * ul: { * type: 'wrap' * tags: [ * '<li>这是UL列表的第1项</li>', * '<li>这是UL列表的第1项</li>', * '<li>这是UL列表的第1项</li>', * '<li>这是UL列表的第1项</li>', * ] * } * } */ ``` ### 4. index.js - 主要插件代码 - 插件一般都是new使用 - 所以是一个类 1. 用户需要传入两个参数 1. 要解析的markdown文件路径 1. 打包后生成的html文件名 2. 用户没有指定编译模板需要抛出错误,默认生成文件名`md.html` 2. webpack为每个plugins插件提供了一个方法apply并传入一个编译器参数 1. 编译器下边有一个hooks在下边存在emit中有个一tap方法 1. 第一个参数插件名 1. 第二个汇编结果 4. 默认打包后的汇编文件只有一个app.js ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22065308/1651046023508-63672def-85d8-427f-bb6a-a46de24fe028.png#clientId=ud5ccf0d2-a961-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=834&id=u7dd1c512&margin=%5Bobject%20Object%5D&name=image.png&originHeight=834&originWidth=1583&originalType=binary&ratio=1&rotation=0&showTitle=false&size=121975&status=done&style=none&taskId=ued369d79-7ab1-4811-a451-6252665466f&title=&width=1583) 5. 获取markdown文件内容 5. 获取当前模板文件内容 5. 将markdown文件中的内容按照一行一行存储到数组中 5. 调用编译方法将markdown字符编译成html字符串 1. 需要先将数组数据转换成树形结构数据 1. 利用正则匹配出每种markdown语法类型 1. 为每种语法对应每种html标签 1. 相同的markdown为同一分组下的 1. 还需要使用随机数,区分相同的标签 2. 遍历数据,按照树中type的不同拼接html字符串 2. 最后将拼接完成的html字符串返回 9. 将html文件中的注释替换成markdown转换后的html字符串 9. 在汇编文件上添加用户配置的文件名 1. 打包后会生成新文件 ```javascript const { readFileSync } = require('fs'); const { resolve } = require('path'); const { compileHTML } = require('./compiler'); const INNER_MARK = '<!-- inner -->'; class MdToHtmlPlugin { constructor({ template, filename }) { // 用户没有传入模板 抛出错误 if(!template) { throw new Error('The config for "template" must be configured'); } this.template = template; this.filename = filename ? filename : 'md.html'; } // webpack为每个插件提供一个方法apply // 编译的过程中都是在apply中做的 // 有一个参数编译器 compiler apply(compiler) { // 编译器 下的hooks 下有个发射器 compiler.hooks.emit.tap('md-to-html-plugin', (compilation) => { const _assets = compilation.assets; // 读取用户webpack中配置的模板文件 const _mdContent = readFileSync(this.template, 'utf8'); // 读取模板html const _templateHTML = readFileSync(resolve(__dirname, 'template.html'), 'utf8') // 将md文件一行一行的存储到数组中 const _mdContentArr = _mdContent.split('\n'); // 编译md字符串为html字符串 const _htmlStr = compileHTML(_mdContentArr); console.log(_htmlStr); // 将注释替换成md字符串转换成的html字符串 const _finalHTML = _templateHTML.replace(INNER_MARK, _htmlStr); // 在_assets上增加资源 _assets[this.filename] = { source() { // 方法返回一个资源 return _finalHTML; }, size() { // 一般return 资源的长度 return _finalHTML.length; } } // console.log(_assets); }) } } module.exports = MdToHtmlPlugin; ```

简介

简易markdown转换html webpack 插件plugins 展开 收起
JavaScript 等 2 种语言
ISC
取消

发行版

暂无发行版

贡献者

全部

近期动态

加载更多
不能加载更多了
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/gaotengjun/md-to-html-plugin.git
git@gitee.com:gaotengjun/md-to-html-plugin.git
gaotengjun
md-to-html-plugin
md-to-html-plugin
master

搜索帮助

A270a887 8829481 3d7a4017 8829481