模版指的就是template属性。vue内部会将template字符串转化成render函数进行渲染。render函数返回虚拟节点,再将虚拟节点转化成真实DOM。(模版=>方法=>节点)
而编译过程就是template转换render函数的过程。
因为将template
转化成render
方法需要在运行时进行编译操作,会有性能损耗。同时引用带有compiler
包的vue体积也会变大。默认.vue文件中的template处理是通过vue-loader
来进行处理的,并不是通过运行时的编译。(默认vue项目中引入的vue.js是不带有compiler模块的。)
vue-loader的作用就是可以把一个模版变成一个对象。内部用到一个NPM包:《vue-template-compiler
》 (插槽、指令等也是用的这个包来处理的,可以自己安装包看下)
包内VueTemplateCompiler.compile
就是用来将模版转化成AST语法树的。
let {ast, render, staticRenderFns} = VueTemplateCompiler.compile('<div>gjf</div>')
该方法返回结果是一个对象:
{
ast: ast,
render: code.render, // 将ast语法树格式化成with函数
staticRenderFns: code.staticRenderFns
}
其中ast就是一颗由对象描述的AST语法树
(见下图),该树用来描述template结构。
image
由ast生成如下字符串
with(this){return _c('div',[_v("gjf")])} // _c是创建元素、_v是虚拟节点
最后,new Function + with语句后生成render方法。render方法执行完毕后生成的是虚拟dom。
new Function + with语句
template => ast => codegen得到上述字符串 => new Function(render) + with语句生成真正的render方法来执行
模版引擎的实现原理就是new Function + with语句来进行实现的。
github:src/compiler/index.js:8
// `createCompilerCreator` allows creating compilers that use alternative
// parser/optimizer/codegen, e.g the SSR optimizing compiler.
// Here we just export a default compiler using the default parts.
var createCompiler = createCompilerCreator(function baseCompile (
template,
options
) {
var ast = parse(template.trim(), options); // 将代码解析成ast语法树
if (options.optimize !== false) {
optimize(ast, options); // 优化代码,标记静态节点。核心就是标记树
}
var code = generate(ast, options); // 生成代码
return {
ast: ast,
render: code.render, // 将ast语法树格式化成with函数
staticRenderFns: code.staticRenderFns
}
});