开始的开始
开始前先说下需求背景;使用 vuepress 写api文档,不同环境下静态资源存放的路径不同,希望可以支持不同环境下的路径下;
markdown-it
了解到 vuepress 使用 markdown-it 来处理 .md 文件,首先想到的就是在 markdown-it 这里下功夫,根据构建环境动态生成部分 .md 文件中的路径(测试环境和正式环境在静态服务的路径不同);
vuepress 配置 markdown-it
在 vuepress 配置文件中(config.js)的导出对象中多加一个 markdown 的属性;其中可以添加一些针对 markdown-it 相关配置的选项;这里我们关注的是 markdown-it 的插件使用,所以首先要找到插件的配置入口,也是为了后边方便测试;
// vuepress config.js
module.exports = {
markdown: {
// markdown-it-anchor 的选项
anchor: { permalink: false },
// markdown-it-toc 的选项
toc: { includeLevel: [1, 2] },
extendMarkdown: md => {
// 使用更多的 markdown-it 插件
md.use(require('markdown-it-xxx'))
}
}
}
markdown-it
查阅了一些资料,并没有发现比较靠谱权威的插件开发指南,便参考了已有的插件;大概以下几点吧
- markdown-it 插件是一个函数;
- 函数接收一个参数(md)理解为当前 markdown-it 实例对象,上边存放了 markdown-it 的配置和解析到的数据(state);
- markdown-it 插件需要往实例对象中添加解析规则,每条解析规则同样是一个函数;
- 解析规则函数会接收当前一个state(当前解析到的数据)参数,插件的意义在于可以根据需求自由修改state的数据
- 目前看到支持添加规则的场景(可能不全):
- md.core.ruler.push('xx', () => {})
- md.renderer.rules.xx = () => {}
- md.block.ruler.push('xx', () => {})
- md.inline.ruler.push('xx', () => {})
- md.inline.ruler2.push('xx', () => {})
- ...
- ruler 除了支持 push,还支持 after、before、disable、enable 等方法;
// 示例代码
// 下边代码则是修改了开始提到的 md 文件中的路径
const markdownItPlugin = md => {
md.core.ruler.push('my_rule', function (state) {
state.tokens.forEach(token => {
const { type, content } = token;
if (type === 'html_block' && content.startsWith('<HtmlRunner')) {
token.content = content.replace(
/\/examples\//,
`${process.env.BUILD_ENV === 'daily' ? '/test' : ''}$&`
);
}
});
});
};
个人愚见
markdown-it 插件个人理解和 ast 类似,先解析目标文件,使用类似抽象语法树(tokens)的形式来描述目标文件语法,后边提供可以修改 tokens 的能力,最后将修改后的 tokens 生成文件;
最后的最后
大功告成!markdown-it 插件在构建层面解决了问题,来个快乐水犒劳下自己吧;这时不知道为什么(想不起来了)又看起了vuepress 的文档,文档中发现了一个帮助函数$withBase
(它被注入到了Vue的原型上);还记得开始的问题吗?支持不同环境下的路径下,根据环境构建同样使用了 base 配置;
问: 直接用这个是不是就解决了开始的问题?
答案: 是的。。。(小丑竟是自己)
最后符上大佬的表情包