请简述 Vue 中模板编译的过程

1,256 阅读1分钟

一、目的

模版编译的目的就是将模版template转换成渲染函数render

AST: 对象形式描述的树形代码结构

  • 模板编译是将字符串模板转换成AST对象
  • 优化AST对象,过程是标记静态根节点
  • 优化好的AST转换成字符串形式代码,之后通过newFunction转换成方法
  • 这方法就是最终的render函数
一、入口函数compileToFunctions(template, ...)
  • 位置 src/platforms/web/entry-runtime-with-compiler.js
/**
 * 把模版编译成render函数
 * @param {*}
 * @return {*}
 */
Vue.prototype.$mount = function (
...
      // 把 template 转换成 render 函数
      const { render, staticRenderFns } = compileToFunctions(template, {
       ...
      }, this)
      ...
  // 调用 mount 方法,渲染 DOM
  return mount.call(this, el, hydrating)
}
  • 调用createCompiler(baseOptions)
  • 调用createCompilerCreator
// `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.
export const createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: CompilerOptions
): CompiledResult {
  // 把模板转换成 ast 抽象语法树
  // 抽象语法树,用来以树形的方式描述代码结构
  const ast = parse(template.trim(), options)
  if (options.optimize !== false) {
    // 优化抽象语法树
    optimize(ast, options)
  }
  // 把抽象语法树生成字符串形式的 js 代码
  const code = generate(ast, options)
  return {
    ast,
    // 渲染函数
    render: code.render,
    // 静态渲染函数,生成静态 VNode 树
    staticRenderFns: code.staticRenderFns
  }
})
三、compile(template, options)
  • 合并options
  • baseCompile(template.trim(),finalOptions)
三、baseCompile(template.trim(),finalOptions)
  • parse(template.trim(), options) 把模板转换成 ast 抽象语法树
  • optimize(ast, options)
    • 标记AST tree树种的静态节点
    • 检测到静态节点、设置为静态、不需要在每次重新渲染时重新生成节点
    • patch静态跳过静态节点
  • generate(ast, options) 把抽象语法树生成字符串形式的 js 代码
四、compileToFunctions(template, ...)
  • 继续把上一步生成的JS代码转换成函数
  • createFunction
  • render和 staticRenderFns初始化完毕, 挂载到vue实例的options对应的属性中