[Vue源码分析] 模板的编译
最近小組有個關于vue源碼分析的分享會,提前準備一下…
前言:
Vue有兩個版本:Runtime + Compiler 、 Runtime only ,前者是包含編譯代碼的版本,后者不包含編譯代碼,編譯過程需要借助webpack的vue-loader,接下來分析的是Runtime + Compiler版本,編譯過程感覺挺復雜的,所以下邊只是大概分析一下整個流程,源碼理解直接寫在源碼中。
模板的編譯
之前分析Virtual DOM的時候我們分析過模板到真實 DOM 渲染的過程,中間有一個環(huán)節(jié)把模板編譯成render函數(shù),這個過程稱作編譯。
(1)編譯入口追蹤
編譯入口在分析virtual dom的時候已經(jīng)提及過,位于src/platforms/web/entry-runtime-with-compiler.js下的$mount方法(紅框部分):
可以看到compileToFunctions方法將模板編譯成了render以及staticRenderFns函數(shù),通過對象的解構賦值獲取結果并賦值給options。
compileToFunctions在 src/platforms/web/compiler/index.js中定義,如下:
發(fā)現(xiàn)這是一個賦值的過程,值由createCompiler產生,createCompiler方法在 src/compiler/index.js 中定義,如下:
這個方法是createCompilerCreator的返回值,createCompilerCreator中傳入的參數(shù)是一個方法,在此暫時不看參數(shù)方法里邊的內容,因為這里只是一個調用,并沒有執(zhí)行什么。先看看createCompilerCreator的定義,它的定義在src/compiler/create-compiler.js中,如下:
createCompilerCreator返回一個 createCompiler 的函數(shù),該函數(shù)返回的是一個對象,包括 compile 和compileToFunctions , compileToFunctions對應的就是$mount方法中調用的compileToFunctions 方法,它是 createCompileToFunctionFn 方法的返回值,我們接下來看一下 createCompileToFunctionFn 方法,它的定義在 src/compiler/to-function/js 中,這個函數(shù)便是compileToFunctions的最終定義,如下:
compileToFunctions中編譯的核心是compile的調用,compile是通過參數(shù)的方式傳入的,也就是createCompilerCreator中定義的compile,現(xiàn)在我們返回去看compile是什么,之前的圖折疊了,現(xiàn)在展開如下:
compile前部分代碼都是在處理配置參數(shù),實際上的編譯過程只有代碼中紅框部分,也就是調用baseCompile方法,這個方法時調用createCompilerCreator時通過參數(shù)的方式傳入的,也就是之前介紹到的當時說暫時不用看的代碼,重新上一次圖:
編譯入口追蹤到這里告一段落(vue項目支持多個平臺,不同平臺配置不一樣,所以入口繞了很多個圈)??梢钥吹阶罱K主要步驟有三步,一步是通過parse生成ast樹,一步是optimize,看英文意思及傳入?yún)?shù)應該是對ast樹進行優(yōu)化的一個過程,一步是調用generate生成code,接下來看看這幾個步驟都干了什么。
(2) parse
編譯過程首先就是對模板做解析,生成 AST語法樹,我們可以在parse后debugger一下,看看AST語法樹的模樣。
新建一個vue demo,在main.js做如下配置:
然后再源碼中parse后打個斷點,或者打印一下:
可以看到,控制臺輸入了以下內容,這便是ast的結構:
至此ast的結構我們了解了,但ast是怎么生成的呢?接下來我們看看parse是什么。parse的定義位于src/compiler/parser/index.js中。
這個過程很復雜,概括地說就是把template模板字符串轉換成AST樹,它是一種用JavaScript對象的形式來描述整個模板。整個parse的過程是利用正則表達式順序解析模板,當解析到開始標簽、閉合標簽、文本的時候都會分別執(zhí)行對應的回調函數(shù),最終達到構造AST樹的目的。
這塊內容很多,挑幾個點講一下:
①:解析標簽
解析HTML是通過調用parseHML方法完成的,它的定義位于src/compiler/parser/html-parser
調用:
定義:
這個方法也是比較復雜,整體來說就是循環(huán)解析template ,用頂部預先定義好的一堆正則表達式做正則匹配,處理開始標簽和結束標簽,對于不同情況分別進行不同的處理,直到解析完畢。
比較關鍵的一個點事在匹配的過程中會利用 advance 函數(shù)不斷前進整個模板字符串,直到字符串末尾。
舉個例子:
假如模板本來是這個樣子的,可以理解為一個隊列,目前隊列的索引為0:
通過調用advance(4)后,通過html.substring(4),隊列的索引就變成了4,當前待解析模板就變成了如下:
②:解析文本、表達式
除了處理開始標簽和結束標簽,還需要處理文本,通過parseText實現(xiàn),源碼位于src/compiler/parser/text-parsre.js
回頭看看之前打印出來的ast,可以看到打上標記的表達式:
③:解析指令,以v-for為例
v-for指令解析的入口是processFor方法,該方法定義位于src/compiler/parser/index.js,此方法依賴parseFor以及extend方法,共同完成v-for的解析。
大概思路:通過正則匹配v-for,匹配到了就調用parseFor方法,parseFor方法位于同文件中:
這個方法也是通過正則匹配,分別匹配出不同的內容,比如’v-for="(item, index) in data"’,匹配出來的res.for是data,res.alias是item,res.iterator是index,隨后返回解析出來的 結果,傳給processFor中的res常量res,接著調用extend方法完成解析,extend方法的定義位于src/shared/util.js中,如下:
其實extend只是一個循環(huán),把之前解析出來的屬性循環(huán)出來并掛載到傳入的ast對象上。(更新于2019.02.25 )
更多指令的解析有興趣可以自行研究一下~~
總結
以上是生活随笔為你收集整理的[Vue源码分析] 模板的编译的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 郑好办
- 下一篇: 为什么王者荣耀英雄战力越加越少