前端工程中的編譯時優化

IT大咖說發表於2018-05-25
前端工程中的編譯時優化

內容來源:2017年7月15日,前端框架《Vue.JS》作者尤雨溪在“2017 JavaScript中國開發者大會”進行《前端工程中的編譯時優化》演講分享。IT 大咖說(微信id:itdakashuo)作為獨家視訊合作方,經主辦方和講者審閱授權釋出。

閱讀字數:1876 | 6分鐘閱讀

嘉賓演講視訊及PPT回顧:suo.im/4TcEw

摘要

通過對壓縮器、打包工具,以及模板引擎處理的講解,來更深入的理解編譯時優化是如何作用的。同時詳細介紹了Vue是如何處理編譯時優化的。以及未來前端領域在編譯時上能做出那些更出色的優化。

前端開發編譯現況

在一段時間之前前端是沒有編譯這回事的,大部分人都是開啟一個頁面就開始寫。但是隨著前端越來越複雜,開發前端時新增的部分越來越多,NodeJs、Webpack、BABEl等變得必不可少,同時Css也要進行預處理。到了現在編譯已經成了前端開發中不可或缺的一環。

壓縮器

編譯是一個語言到另一個語言表達的轉變,這裡面不僅僅是功能上的應用,比如說從ES6轉化到ES5,還可以給程式帶來效能上的優化。

目前所有的編譯器都是先將原始碼Parser成AST(抽象語法樹),然後對AST進行分析,在這個分析過程中進行各種優化。

程式碼壓縮其實就是一個構建時優化,我們通常使用的壓縮器就相當於編譯器,它將原生的程式碼壓縮成更簡潔、更輕量的形式。常見的壓縮器有Closuer Compiler、UglifyJS、Babili、Butternut。這裡面UglifyJS不僅僅是一個壓縮器,它自己還實現了一套JS Parser,擁有一套程式碼生成系統,等於是構建了一個完整的編譯工具鏈。Babili則是基於BABEL的外掛實現的。

由此我們可以從一直使用的壓縮器中感受到編譯時優化是怎麼樣的一個作用過程。

Bundlers(打包工具)

早先的程式碼維護是非常不方便的,所以就出現一些打包工具,倡導開發者使用模組,使得程式碼能夠更好的維護。但是另一個問題出現了,打包後程式碼變得難以壓縮。這是因為早期的打包工具每一個模組都是包含在一個函式作用域內的,對於壓縮器來說每一個作用域都是分離的,在進行優化的時候很多部分都無法完成。

針對上面的問題Rollup這類的工具就誕生了,只要是使用了ES模組,它就可以讓所有的模組都放在同一個作用域中,這樣壓縮器就有用武之地。

AOT VS JIT

在使用模板引擎的時候,通常都會將模板直接寫在JavaScript裡面,模板字串會被編譯成JavaScript程式碼,這個過程一般都是在瀏覽器上進行的,但是這樣就會增加使用者的等待時間。

其實這個編譯的過程完全可以放在構建時進行,由此AOT和JIT出現了。JIT在構建時並不編譯而是直接將模板傳送到瀏覽器裡,當需要使用的時候再進行編譯。AOT則是在構建的時候提前進行編譯。

Angular、Vue、Glimmer就是一個典型構建時編譯的例子,編寫的時候是模板而當編譯完成後傳送出去的卻是JavaScript程式碼。Angular使用AOT達成這一目標,Vue在使用Vue-loader時候預設就是這樣執行的。

Vue的編譯時優化

靜態元素

前端工程中的編譯時優化

在生成Vue的渲染函式的時候,直接將靜態元素存在一個陣列裡面,然後通過 return this._renderStatic(0) 來永遠返回同一個片段,同樣也可以跳過比對的過程。

前端工程中的編譯時優化

對於Vue的template模板中的靜態class,在生成程式碼中會作為staticClass出現。

服務端渲染

前端工程中的編譯時優化

在服務端渲染的時候,Virtual DOM是比不上字串模板的。Vue會分析模板找出可以被拼接成字串的部分直接進行拼接,而不能拼接的部分還是使用Virtual DOM。這樣就可以使服務端渲染獲得效能提升。

前端工程中的編譯時優化

單頁應用的包有時候會很大,整個下載下來的話對使用者來說效能上是不友好的。理想情況應該是在訪問某個單頁應用的時候只下載所訪問的頁面的JavaScript程式碼,要實現這樣的效果就需要將程式碼切分成塊。

Webpack的code-split功能就可以達到這一目標,由此我們就會獲得多個javascript檔案。由於所有的關聯資訊都是在main.js裡面,只有先載入main.js後才會知道後續要載入是哪個js檔案,這就造成了在服務端渲染的時候會有一次額外的載入,並造成延時。

在Vue的SSR裡面客戶端和服務端分別會有一次渲染。在客戶端渲染的時候除了生成分割開的程式碼塊之外,還會生成一個資訊檔案,包含了這次構建的這些模組對應的資訊。而服務端的渲染會生成一個Server Bundle.js以及同樣的資訊檔案。這樣Vue在build之後就會獲得服務端構建和客服端構建的關聯資訊,通過分析就可以在服務端獲得一個請求的時候去計算出客戶端應該需要的是哪些檔案,而不需要去先載入main.js。

前端工程中的編譯時優化

一般來說服務端渲染中Css是需要提前載入的,否則的話頁面是沒有樣式的。但是由於Css的檔案較大,提前載入的話使用者等待時間就會變長。解決方案就是提前載入一些關鍵的Css,要達到這一目的就需要在編譯時提取這些Css。

而在Vue的單檔案元件中Style部分會被抽取出來,於生成的JavaScript內是以動態的形式在該元件的生命週期鉤子裡去進行注入,也就是說在服務端渲染的時候只有用到的元件的Css樣式才會被載入。

期望實現的想法

在編譯時分析Vue的所有元件的原始碼,來找出那些功能沒有用到,然後將Vue原始碼內這些用不到的部分去除掉,這樣就可以更進一步的精簡程式碼生成量。


相關文章