跳到主要内容

解决markdown-it-prism未能正确加载Languages的BUG

· 阅读需 4 分钟

hexo博客同步至csdn - 木然轩一文中,我提到了prismjs在尝试渲染C++代码块时不能正确加载node_modules/prismjs/components/prism-cpp.js。于是,我在prismjs的GitHub项目上提交了Pull Request:cpp extend clike by jlice · Pull Request #1914 · PrismJS/prism。不过,prismjs的项目维护者却告诉我,这锅prismjs不背,是markdown-it-prism自己的问题。

其实在提交这个Pull Request时我也觉得奇怪,prismjs的用户基数那么大,而C++也是非常常见的语言,要是出现这种问题早就解决了。不过,我的确是在一顿Debug后找到了出错的位置,但这个出错的位置是错误的果,未必是错误的因。

prismjs

prismjs是一个代码块高亮的库,其作用和highlight.js差不多,有点像Python里的Pygments。大致看了下prismjs的源码,感觉主要就是用正则表达式描述了各编程语言的文法,然后做词法分析,对各种类型的token应用相应的样式。下面是prismjs的目录结构:

components目录是对各语言的定义,plugins是一些功能增强插件,themes就是主题了。例如,prism/components/prism-cpp.js中就定义了C++的文法:

Prism.languages.cpp = Prism.languages.extend('c', {
'class-name': {
pattern: /(\b(?:class|enum|struct)\s+)\w+/,
lookbehind: true
},
...

它扩展自C。类似地,在prism/components/prism-c.js中定义了C的文法:

Prism.languages.c = Prism.languages.extend('clike', {
...

而clike没有扩展自别的语言,应该在prism作为一种基本的语言类型。

在Debug的过程中,我在prism/components/prism-core.js中发现了DFS递归查找语言定义。心想,都有DFS了,怎么就不能正确加载呢,路径都没问题呀。

loadPrismLang

prismjs维护者提示,找到了问题之所在。位于markdown-it-prism/index.js的loadPrismLang函数内

require('prismjs/components/prism-' + lang);

对于C++,lang的值应是cpp。这里它就直接调用prismjs/components/prism-cpp这个模块了,可根据前面的分析,它extend自prism-c,而prism-c又extend自prism-clike。因此,像这样直接调用会出错的,应该使用prismjs里提供的loadLanguages,它可以自动处理依赖关系。在prismjs官方文档上也提到了这一点:

这个函数定义在prism/components/index.js。于是乎,就给markdown-it-prism提交了个Pull Request

如果通过npm安装markdown-it-prism,可以发现index.js位于build目录下,而markdown-it-prism的GitHub项目里,index.js位于项目的根目录,而且这两个index.js的内容不一样。通过查看项目下的package.json,可以了解到项目是使用babel编译的,用mocha来测试的。编译、测试一下,一切OK。结果GitHub用TravisCI跑一下,在老版本Nodejs上未能通过测试:

不过,这并不代表修改是错误的,也许是测试用例没有更新。

Pull Request

markdown-it-prism项目的维护者Merge了我的Pull Request:

而且,也添加了我的测试用例。