Vue 2.0 模板編譯源碼分析

本文基于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
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容