Vue

Vue 2.0 模板编译源码分析

2017-09-28  本文已影响121人  fehysunny

本文基于vue-2.4.4源码进行分析

模板编译是Vue 2.0中很重要的一个环节,它将template编译成render 函数,最后生成Virtual DOM渲染在页面。

本篇文章将结合源码对模板编译流程进行分析:

从源码角度看,模板编译主要经历如下流程:

vue-compile.png

即:

首先,在项目初始化时挂载DOM节点获取template

然后将 template 编译成 render 函数。这个编译过程包含:

  1. check 缓存,如果有缓存数据就读取缓存数据
  2. 获取并合并options
  3. parse: 将template解析成AST
  4. optimize: 标记静态节点
  5. generate: 拼接 render function 字符串
  6. 通过 new function 生成渲染函数
  7. 缓存

其中,3、4、5是整个模板编译的核心。

baseCompile函数(src/compiler/index.js)依次执行parseoptimize,和generate,最后返回一个包含astrenderstaticRenderFns的对象。

export const createCompiler = createCompilerCreator(function baseCompile (
  template: string,
  options: CompilerOptions
): CompiledResult {
  // 3. parse: 将template解析成AST
  const ast = parse(template.trim(), options)
  // 4. optimize: 标记静态节点
  optimize(ast, options)
  // 5. generate: 拼接 render function 字符串
  const code = generate(ast, options)
  return {
    ast,
    render: code.render,
    staticRenderFns: code.staticRenderFns
  }
})

parse: 将template解析成AST

这里,先简单介绍下AST。

AST全称是:Abstract Syntax Tree (抽象语法树),是源代码语法所对应的树状结构。Vue 2.0中ASTNode有三种形式:ASTElementASTTextASTExpression

Vue 2.0中的parse函数(src/compiler/parser/index.js)采用了jQuery作者John ResigHTML Parser

parseHTML(template, {
  start (tag, attrs, unary) {
    // 解析到新的节点时调用,包括节点tagName, attributes等信息
  },
  end () {
    // 节点解析结束时调用,包括节点tagName等信息
  },
  chars (text: string) {
    // 文本解析完成时调用,包括文本本身
  }
}

如:<div id='app'>{{ message }}</div>

parseHTML后的结果是:

ast.png

optimize: 标记静态节点

optimize函数(src/compiler/optimizer.js)会对静态节点打标,提取最大的静态树,在后面patch时,被标记为static的节点将直接跳过diff。

export function optimize (root: ?ASTElement, options: CompilerOptions) {
  if (!root) return
  isStaticKey = genStaticKeysCached(options.staticKeys || '')
  isPlatformReservedTag = options.isReservedTag || no
  // first pass: mark all non-static nodes.
  markStatic(root)
  // second pass: mark static roots.
  markStaticRoots(root, false)
}

generate: 拼接 render function 字符串

generate函数(src/compiler/codegen/index.js)

export function generate (
  ast: ASTElement | void,
  options: CompilerOptions
): CodegenResult {
  const state = new CodegenState(options)
  const code = ast ? genElement(ast, state) : '_c("div")'
  return {
    render: `with(this){return ${code}}`,
    staticRenderFns: state.staticRenderFns
  }
}

总结

模板编译的核心:templateASTrender function

vue-comile-flow.png
上一篇下一篇

猜你喜欢

热点阅读