前言
前端很多时候会用到markdown格式转html标签的需求,至少我自己有遇到过,就是我第一个博客后台项目,是用的md格式写的,写完存储在数据库中,在前台展示的时候会拉取到md字符串,然后通过md2html这样的插件转换成html甚至高亮梅美化过后展示在页面上,效果还是不错的,那么自己来实现一个这样的插件有多困难呢,其实不然。
项目初始化
创建一个工作文件夹,取名就叫md-to-html-plugin
,初始化npm
仓库
1 | mkdir md-to-html-plugin |
引入基础的webpack
依赖,这里我仍然使用4.X版本
1 | "devDependencies": { |
安装依赖
npm i
或者yarn install
修改script脚本
1 | "scripts": { |
根目录下新建webpack.config.js
文件,进行简单配置,并创建对应的测试文件,如:test.md
、src/app.js
1 | const {resolve} = require('path'); |
test.md
1 | # 这是H1标题 |
根目录下创建plugins,存放我们要开发的插件
最终的目录结构如下:
创建MdToHtmlPlugin
1 | class MdToHtmlPlugin { |
初始化的时候接受webpack.config.js
中传入的options,对应一个要解析的md文件,一个解析后的文件路径
预解析
编译过程在apply中执行,我们在这个方法里先粗略的把我们逻辑框架写出来,大概思路如下:
1 | 1. markdown文件 |
解释下就是:
- 把我们要解析的md文件内容读取出来
- 把插件的模板文件读取出来
- 读取后的md文件内容肯定是字符串,如果后期要逐个解析成html的话,肯定是转成数组然后遍历解析比较方便,那就先把读取到的md文件转成数组,即字符串转数组
- 数组解析成html标签
- 把模板中的占位区替换成解析后的html内容
- 把解析完成的文件动态添加到资源中输出到打包路径下
1 | /** |
查看_assets
读取md资源
加载插件html模板
解析md文件成数组格式,方便后续对md文件内容逐行解析
添加资源
compileHTML这个核心的方法还没写,但是大概的框架已经出来了,这里就是要重点掌握一下tapable
这个事件流
什么是webpack事件流?
webpack本质上是一种事件流的机制,它的工作流程就是将各个插件串联起来,而实现这一切的核心就是Tapable。
Webpack 的 Tapable 事件流机制保证了插件的有序性,将各个插件串联起来, Webpack 在运行过程中会广播事件,插件只需要监听它所关心的事件,就能加入到这条webapck机制中,去改变webapck的运作,使得整个系统扩展性良好。
Tapable也是一个小型的 library,是Webpack的一个核心工具。类似于node中的events库,核心原理就是一个订阅发布模式。作用是提供类似的插件接口。
webpack中最核心的负责编译的Compiler和负责创建bundles的Compilation都是Tapable的实例
Tapable类暴露了tap、tapAsync和tapPromise方法,可以根据钩子的同步/异步方式来选择一个函数注入逻辑
compileHTML方法分析
拿到md的内容数组格式后,我们可以将其遍历组装析成树形结构化的数据然后解析成我们想要的html结构,分析完md数据特点,可以大概转化成如下的树形结构:
1 | /** |
plugins目录下创建compiler.js
文件,里面暂时只有一个compileHTML
方法
1 | function compileHTML(_mdArr) { |
编译树
匹配H标签
1 | // 匹配md每行开头的标符 |
打印_htmlPool看看是否正确生成预期的树结构:
匹配无序列表
1 | // 匹配无序列表 |
匹配有序列表
1 | // 匹配有序列表(数字) |
html字符串拼接
1 | function compileHTML(_mdArr) { |
预览
npm run dev
后发现dist
目录下生成了app.js
和test.html
,打开test.html
:
1 |
|
浏览器打开预览效果:
写在最后的话
其实实际应用过程中还可以针对特定的标签做css美化,例如微信公众号的编辑器,可以看到每个标签都会有响应的样式修饰过,原理不变,js秀到底层就是操作字符串。
- 本文链接:https://cong1223.github.io/2021/02/09/%E6%89%8B%E5%86%99%E8%87%AA%E5%B7%B1%E7%9A%84webpack%E6%8F%92%E4%BB%B6%E3%80%8Eplugin%E3%80%8F/
- 版权声明:本博客所有文章除特别声明外,均默认采用 许可协议。
若没有本文 Issue,您可以使用 Comment 模版新建。
GitHub IssuesGitHub Discussions