vue3的學習已經有一段時間了,本着奔浪不奔就可能變成後浪的態度,學習梳理了下vue3的編譯,基於vue3的整個編譯源碼的學習,準備把編譯源碼按照編譯過程分三部分記錄學習下來,同各位奔浪一塊兒奔跑.....html
一、目錄結構前端
上面是整個代碼的目錄結構以及相關文件的主要做用,與模板編譯相關的核心代碼是compiler-core 中的整個目錄,vue3源碼鏈接奉上:github.com/vuejs/vue-n…vue
二、編譯入口
/vue/src/index.tsgit
在完整版的 index.js
中,調用了 registerRuntimeCompiler
將 compile
注入編譯方法,即爲模板編譯的入口,固然其中還有一些其餘的判斷,有興趣的能夠進入繼續查看源碼github
vue2編譯web
vue3編譯babel
整個編譯流程其實主要分爲三部分:整個編譯過程跟vue2的編譯的過程有markdown
template模板字符串 ----》編譯爲最基礎的AST ----> transform基礎AST增長patchflag等熟悉 ----》 generate基於AST生成render函數數據結構
<div name="test">
<!-- 這是註釋 -->
<p>{{ test }}</p>
一個文本節點
<div>good job</div>
</div>
複製代碼
vue2編譯後結果:函數
function render() {
with(this) {
return _c('div', {
attrs: {
"name": "test"
}
}, [_c('p', [_v(_s(test))]), _v("\n 一個文本節點\n "), _c('div', [_v(
"good job")])])
}
}
複製代碼
vue3編譯後結果:
import {
createCommentVNode as _createCommentVNode,
toDisplayString as _toDisplayString,
createVNode as _createVNode,
createTextVNode as _createTextVNode,
openBlock as _openBlock,
createBlock as _createBlock
} from "vue"
const _hoisted_1 = {
name: "test"
}
const _hoisted_2 = /*#__PURE__*/ _createTextVNode(" 一個文本節點 ")
const _hoisted_3 = /*#__PURE__*/ _createVNode("div", null, "good job", -1 /* HOISTED */ )
export function render(_ctx, _cache, $props, $setup, $data, $options) {
return (_openBlock(), _createBlock("div", _hoisted_1, [
_createCommentVNode(" 這是註釋 "),
_createVNode("p", null, _toDisplayString(_ctx.test), 1 /* TEXT */ ),
_hoisted_2,
_hoisted_3
]))
}
複製代碼
經過對比發現最終都返回render函數,可是render函數的結構和樣式上有了很大的差異,同時有了特殊的含義註釋,在接下來的過程當中咱們會一點點接口神祕面紗....
源碼的第一部分 baseParse主要的做用就是將 template模板字符串編譯爲基礎AST樹,可是咱們能夠思考下他說怎麼轉換生成的呢?
(1)、類比前端模板引擎
(2)、類比babel編譯過程
(3)、vue3解析
之因此用前端模板和bable的編譯過程來類別vue3的編譯,其實他們是有不少共性的,
好比:前端模板編譯
const data = {
'title':'模板標題',
'content':'模板內容'
}
const temp = '
<div>{{d.title}}</div>
<div>{{d.content}}</div>
複製代碼
這種 data + temp---》html的 很容易想到基於正則的進行匹配替換。
好比:bable編譯
function test(){
const a = b
}
複製代碼
這個函數字符串如何進行詞法解析 、預發解析呢?其實也是基於正則不斷的對字符串進行選擇、截取、 匹配.....直到最有一個字符完成,function等關鍵字等同於div等標籤的關鍵字,函數的"{"(開始左括號) 和 」}「(結束右括號) 等同於div標籤的"
vue3中將template--->baseParse解析爲AST的過程也是同樣的:
四、父子關係
單純的正則匹配和解析只是獲取了標籤自己的屬性、特性等數據,可是template自己的標籤是有父子層級關係的,標籤與標籤直接的關係怎麼來維護呢?瞭解過webkit渲染原理的應該很容易想到,棧:一個先進後出的數據結構
//解析過程當中:
<div name="test">
<!-- 這是註釋 -->
<p>{{ test }}</p>
一個文本節點
<div>good job</div>
</div>
複製代碼
vue3的第一部分實際上是不斷將模板字符串經過正則去解析、截取、匹配特殊數據和屬性......過程,同時在解析中用棧的形式維護保存正在解析的標籤