此文针对 vue-loader@13.7.2 版本。 后续版本如果对应实现没有大的变化,也适用。
模板编译相关代码见 vue-loader/lib/template-compiler
preprocessor
通过引入 consolidate 库对 template 进行预处理来支持比如pug
,njk
等 html 模板语言。
const cons = require('consolidate')
const loaderUtils = require('loader-utils')
module.exports = function (content) {
this.cacheable && this.cacheable()
const callback = this.async()
const opt = loaderUtils.getOptions(this) || {}
if (!cons[opt.engine]) {
return callback(
new Error(
"Template engine '" +
opt.engine +
"' " +
"isn't available in Consolidate.js"
)
)
}
// allow passing options to the template preprocessor via `template` option
if (this.options.__vueOptions__) {
Object.assign(opt, this.options.__vueOptions__.template)
}
// for relative includes
opt.filename = this.resourcePath
cons[opt.engine].render(content, opt, (err, html) => {
if (err) {
return callback(err)
}
callback(null, html)
})
}
所以其实 SFC 中可以支持自己喜欢的任意 consolidate
支持的模板语言。
我的选择是 nunjucks
从上面的代码我们可以看出。可以通过在 vueOptions
中增加 template
配置项来将模板渲染的配置传递给 render
函数。
比如 vue-loader.conf.js
中可以这样写。
module.exports = {
loaders: loaders,
transformToRequire: {
video: "src",
source: "src",
img: "src",
image: "xlink:href"
},
template: {
}
};
但是值得注意的是这个 options
传递给的是 render
函数。
由于 nunjucks 中的 变量插值语法跟 vue 的模板的想冲突。
所以我想修改 nunjucks
中的语法。因为 nunjucks
毕竟使用场景比较少一些。
实现自定义 nunjucks 变量插件语法
通过查看 nunjucks
的源代码发现,nunjucks
默认使用了一个全局的 Enviroment
配置。
也就是说可以在 webpack
打包运行开始时对 nunjucks
进行配置,因为他们都在同一个进程中运行,全局变量的修改可以影响后续的代码执行。
所以可以在 vue-loader.conf.js
中进行如下配置。
- 导入
nunjucks
const nunjucks = require("nunjucks");
- 配置
nunjucks.configure( {
tags: {
variableStart: '<$',
variableEnd: '$>',
}
});
最终 It Works