09-Vue是如何将模板进行编译的

1,938 阅读2分钟

模板编译

1.概念

模板编译的主要目标是将模板(template)转换为渲染函数(render)

2.模板编译的必要性

vue2.0需要用到VNode描述视图以及各种交互,让开发者手写render函数是不太可行的,因此只需要开发者编写类似HTML代码的vue模板,通过编译器将模板转换为可返回VNode的render函数。

3.模板编译后产出

带编译器的版本中,可以使用template或el的方式声明模板

with(this){return _c('div',{attrs:{"id":"demo"}},[_m(0),_v(" "),(foo)?_c('p',[_v(_s(foo))]):_e(),_v(" "),_c('comp',{on:{"myclick":onMyClick}})],1)}

_c是createElement别名

模板执行的时间点有2个:(带不带编译器)
1)webpack运行时之前提前预编译
2)直接引入vue.js方式,则自带编译器,el或者template,实时进行编译

4.vue源码模板编译的整体流程

1)入口$mount挂载时,compileToFunctions会将template进行编译

位置:platform/web/entry-runtime-with-compiler.js

功能:若指定template或el选项,则会执行编译

Vue.prototype.$mount = function (
  el?: string | Element,
  hydrating?: boolean
): Component {
    const { render, staticRenderFns } = compileToFunctions(template, {
        outputSourceRange: process.env.NODE_ENV !== 'production',
        shouldDecodeNewlines,
        shouldDecodeNewlinesForHref,
        delimiters: options.delimiters,
        comments: options.comments
      }, this)
      options.render = render
      options.staticRenderFns = staticRenderFns
}

2)编译过程

位置:src/compiler/index.js

export const createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: CompilerOptions
): CompiledResult {
  const ast = parse(template.trim(), options)
  if (options.optimize !== false) {
    optimize(ast, options)
  }
  const code = generate(ast, options)
  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})

3)编译三阶段

  • parse(解析)

解析器将模板解析为抽象语法树AST,只有将模板解析成AST后,才能基于它做优化或者撑撑代码字符串

位置:src/compiler/parser/index.js

解析器内部分了HTML解析器、文本解析器和过滤器解析器,最主要是HTML解析器:

parseHTML(tempalte, {
    start(tag, attrs, unary){}, // 遇到开始标签的处理 
    end(){},// 遇到结束标签的处理
    chars(text){},// 遇到文本标签的处理 
    comment(text){}// 遇到注释标签的处理
})

通过Chrome调试工具,得到AST,结构如下:

  • optimize(优化)

    优化器的作用是在AST中找出静态子树并打上标记。静态子树是在AST中永远不变的节点,如:纯文本节点。

    标记静态子树的好处:

    • 每次重新渲染,不需要为静态子树创建新节点
    • 虚拟DOM中patch时,可以跳过静态子树
      <!--要出现嵌套关系--> 
      <h1>Vue<span>模板编译</span></h1>
    

    位置:src/compiler/optimizer.js - optimize

  • generate(生成)

将AST转换成渲染函数中的内容,即代码字符串。

位置:src/compiler/codegen/index.js

code = "_c('div',{attrs:{"id":"demo"}},[_m(0),_v(" "),(foo)?_c('p',[_v(_s(foo))]):_e(),_v(" "),_c('comp',{on:{"myclick":onMyClick}})],1)"