vue模板編譯,源碼調(diào)試過(guò)程

1. 為什么進(jìn)行模板編譯

在vue中,template中可以寫(xiě)表達(dá)式,條件渲染,循環(huán)渲染,點(diǎn)擊事件等,這些在html中是不可以實(shí)現(xiàn)的,只能在js中實(shí)現(xiàn),所以vue對(duì)他進(jìn)行了處理,處理的方法就是模板編譯為render函數(shù),執(zhí)行render函數(shù),返回vnode

2. 模板編譯過(guò)程:

1. 入口compileToFunctions()函數(shù)——src/platforms/web/entry-runtime-with-compiler.js
2. 進(jìn)入compilerToFunctions()函數(shù),src/compiler/to-function.js中的createCompileToFunctionFn()方法

主要作用:

  • 判斷有無(wú)緩存的編譯對(duì)象,如果有直接返回,第一次進(jìn)入時(shí)沒(méi)有緩存
const key = options.delimiters
  ? String(options.delimiters) + template
  : template
// 1. 判斷有無(wú)緩存的編譯對(duì)象compileFunctionResult,如果有直接返回
if (cache[key]) {
  return cache[key]
}
  • compile把模板編譯為編譯對(duì)象(render,staticRenderFns),字符串形式的js代碼
const compiled = compile(template, options)
  • createFunction將字符串形式j(luò)s代碼轉(zhuǎn)換為js方法
res.render = createFunction(compiled.render, fnGenErrors)
res.staticRenderFns = compiled.staticRenderFns.map(code => {
  // 把數(shù)組中每一項(xiàng)轉(zhuǎn)為render方法
  return createFunction(code, fnGenErrors)
})
  • 緩存并返回res對(duì)象
// 4. 緩存并返回res對(duì)象(render,staticRenderFns方法)
return (cache[key] = res)
3. compile主要作用:a. 合并選項(xiàng);b. 調(diào)用baseCompile(template.trim(), finalOptions)

/src/compiler/create-compiler.js——createCompilerCreator()方法

a. 合并選項(xiàng)
// 創(chuàng)建一個(gè)沒(méi)有原型的對(duì)象finalOptions,用來(lái)合入baseOptions和complie傳入的options
const finalOptions = Object.create(baseOptions)
// 編譯過(guò)程中出現(xiàn)的錯(cuò)誤和信息
const errors = []
const tips = []
......
// ?。。aseCompile模板編譯核心函數(shù),把模板編譯成render函數(shù),返回一個(gè)函數(shù)
// 函數(shù)中有兩個(gè)成員,render,staticRenderFns,此時(shí)存儲(chǔ)的是字符串js代碼
const compiled = baseCompile(template.trim(), finalOptions)
b. 調(diào)用baseCompile()方法(src/compiler/index.js——createCompilerCreator(function baseCompile (){...}))
export const createCompiler = createCompilerCreator(function baseCompile (
  // 模板,用戶(hù)傳入的參數(shù)
  template: string,
  options: CompilerOptions
): CompiledResult {
  // 將template轉(zhuǎn)為ast抽象語(yǔ)法樹(shù)
  // parse傳入兩值,去空格的模板,合入的options
  const ast = parse(template.trim(), options)
  if (options.optimize !== false) {
    // 優(yōu)化抽象語(yǔ)法樹(shù)
    optimize(ast, options)
  }
  // 將抽象語(yǔ)法樹(shù)轉(zhuǎn)為 字符串類(lèi)型 js
  const code = generate(ast, options)
  return {
    // 抽象語(yǔ)法樹(shù)
    ast,
    // 渲染函數(shù),此時(shí)的render是字符串形式的,還需要調(diào)用toFunction轉(zhuǎn)為js方法
    render: code.render,
    // 靜態(tài)渲染函數(shù)
    staticRenderFns: code.staticRenderFns
  }
})

主要有3個(gè)作用:

  1. 通過(guò)parse將模板編譯為抽象語(yǔ)法樹(shù)ast

    • 遍歷html,轉(zhuǎn)換為ast對(duì)象,也就是普通對(duì)象
    • 相關(guān)的html指令/屬性記錄在ast相應(yīng)對(duì)象的屬性上

    1. ast,抽象語(yǔ)法樹(shù)
    抽象語(yǔ)法樹(shù),abstract syntax tree,ast;
    使用對(duì)象的形式描述樹(shù)形代碼結(jié)構(gòu);
    此處的ast是描述屬性結(jié)構(gòu)的HTML字符串

    2. 為什么使用抽象語(yǔ)法樹(shù)
    模板字符串轉(zhuǎn)換為ast后,可通過(guò)ast對(duì)模板進(jìn)行優(yōu)化
    標(biāo)記模板中的靜態(tài)代碼,patch的時(shí)候可跳過(guò)靜態(tài)內(nèi)容
    在patch過(guò)程中靜態(tài)代碼不需要對(duì)比和重新渲染
    使用babel也是先將代碼轉(zhuǎn)為ast,再將代碼進(jìn)行降級(jí)

  2. 優(yōu)化抽象語(yǔ)法樹(shù)ast,標(biāo)記靜態(tài)節(jié)點(diǎn)與靜態(tài)根節(jié)點(diǎn)

    • markStatic標(biāo)記靜態(tài)節(jié)點(diǎn),判斷node.type,=2表達(dá)式不標(biāo)記,=3文本靜態(tài)標(biāo)記;=1標(biāo)簽元素,遍歷子節(jié)點(diǎn)標(biāo)記靜態(tài)節(jié)點(diǎn)
    • markStaticRoots標(biāo)記靜態(tài)根節(jié)點(diǎn),靜態(tài)根節(jié)點(diǎn)(標(biāo)簽包含文本,有靜態(tài)子標(biāo)簽;標(biāo)簽只是純文本不是靜態(tài)根節(jié)點(diǎn),因?yàn)閮?yōu)化成本大于收益)
  3. generate將抽象語(yǔ)法樹(shù)轉(zhuǎn)為字符串類(lèi)型的js

    • 通過(guò)genElement生成字符串的js代碼
      1. 判斷staticProcessed,用來(lái)標(biāo)記是否被處理,如果已經(jīng)被處理則不處理
      2. 處理once/if/for轉(zhuǎn)為render指令;template,組件轉(zhuǎn)為字符的js代碼
      3. genChildren完成后生成了render函數(shù)中所需要的代碼,使用_c傳入tag,data,children
    • staticRenderFns靜態(tài)根節(jié)點(diǎn)處理
4. createFunction將字符串形式j(luò)s代碼轉(zhuǎn)換為js方法

src/compiler/to-function.js——createFunction()

function createFunction (code, errors) {
  try {
    // 通過(guò)new Function轉(zhuǎn)為js方法
    return new Function(code)
  } catch (err) {
    errors.push({ err, code })
    return noop
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容