美文网首页Vue
Vue 2.0 模板编译源码分析

Vue 2.0 模板编译源码分析

作者: fehysunny | 来源:发表于2017-09-28 23:37 被阅读121次

    本文基于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

    相关文章

      网友评论

        本文标题:Vue 2.0 模板编译源码分析

        本文链接:https://www.haomeiwen.com/subject/djhbextx.html