手写一个markDown转html的plugin
- 创建package.json
- 生产环境安装webpack三大件
"devDependencies": {
"webpack": "^4.30.0",
"webpack-cli": "^3.3.0",
"webpack-dev-server": "^3.7.2"
}
- 新建webpack.config.js
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"),
filename: "test.html"
})
]
}
- 新建src/app.js plugins/md-to-html-plugin/index.js、template.html、utils.js 等文件
// plugins/md-to-html-plugin/index.js
const { resolve } = require("path")
const { readFileSync } = require("fs")
const { compileHTML } = require("./utils")
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"
}
/**
* 编译其实是apply中做的
* compiler 编译器 下面有相应的钩子集合
* 第一个参数随意,一半是插件名称
* 第二个是回调函数 compilation下有assets 资源
*/
apply (compiler) {
compiler.hooks.emit.tap("md-to-html-plugin", compilation => {
const _assets = compilation.assets
// 需要转换的md文件,剪切成数组替换
const _mdContent = readFileSync(this.template, "utf-8")
const _mdContentArr = _mdContent.split("\n")
// 模板文件,将处理后的数据替换掉预留的插入标记INNER_MARK
const _htmlContent = readFileSync(resolve(__dirname, "template.html"), "utf-8")
const _outContent = _htmlContent.replace(INNER_MARK, compileHTML(_mdContentArr))
// 往资源中增加文件
_assets[this.filename] = {
source () {
return _outContent
},
size () {
return _outContent.length
}
}
})
}
}
module.exports = MdToHtmlPlugin
// plugins/md-to-html-plugin/utils.js
// 空字符串开头 空格结尾 中间必须有字符
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)
if ( matched ) {
const mark = matched[1]
const input = matched["input"]
if ( reg_sharp.test(mark) ) {
const tag = `h${mark.length}`
const tagContent = input.replace(reg_mark, "")
if ( _lastMark === mark ) {
_htmlPool[tag].tags = [..._htmlPool[tag].tags, `<${tag}>${tagContent}</${tag}>`]
} else {
_lastMark = mark
_key = randomNum()
_htmlPool[`${tag}-${_key}`] = {
type: "single",
tags: [`<${tag}>${tagContent}</${tag}>`]
}
}
}
if( reg_crossbar.test(mark) ){
const tag = `li`
const tagContent = input.replace(reg_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: "warp",
tags: [`<${tag}>${tagContent}</${tag}>`]
}
}
}
if( reg_number.test(mark) ){
const tag = `li`
const tagContent = input.replace(reg_mark, "")
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: "warp",
tags: [`<${tag}>${tagContent}</${tag}>`]
}
}
}
}
})
return _htmlPool
}
function compileHTML (_mdArr) {
const _htmlPool = createTree(_mdArr)
let _htmlStr = ""
let item
for (let key in _htmlPool) {
item = _htmlPool[key]
if ( item.type === "single" ) {
item.tags.forEach(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
}
}
return _htmlStr
}
function randomNum () {
return new Date().getTime() + parseInt(Math.random() * 10000)
}
module.exports = {
compileHTML,
randomNum
}
- 修改package.json scripts
"scripts": {
"build": "webpack"
},