內容來源:2017年7月15日,前端框架《Vue.JS》做者尤雨溪在「2017 JavaScript中國開發者大會」進行《前端工程中的編譯時優化》演講分享。IT 大咖說(微信id:itdakashuo)做爲獨家視頻合做方,經主辦方和講者審閱受權發佈。
javascript
閱讀字數:1876 | 6分鐘閱讀前端
嘉賓演講視頻及PPT回顧:suo.im/4TcEw
java
經過對壓縮器、打包工具,以及模板引擎處理的講解,來更深刻的理解編譯時優化是如何做用的。同時詳細介紹了Vue是如何處理編譯時優化的。以及將來前端領域在編譯時上能作出那些更出色的優化。數組
在一段時間以前前端是沒有編譯這回事的,大部分人都是打開一個頁面就開始寫。可是隨着前端愈來愈複雜,開發前端時新增的部分愈來愈多,NodeJs、Webpack、BABEl等變得必不可少,同時Css也要進行預處理。到了如今編譯已經成了前端開發中不可或缺的一環。瀏覽器
編譯是一個語言到另外一個語言表達的轉變,這裏面不只僅是功能上的應用,好比說從ES6轉化到ES5,還能夠給程序帶來性能上的優化。前端框架
目前全部的編譯器都是先將源代碼Parser成AST(抽象語法樹),而後對AST進行分析,在這個分析過程當中進行各類優化。微信
代碼壓縮其實就是一個構建時優化,咱們一般使用的壓縮器就至關於編譯器,它將原生的代碼壓縮成更簡潔、更輕量的形式。常見的壓縮器有Closuer Compiler、UglifyJS、Babili、Butternut。這裏面UglifyJS不只僅是一個壓縮器,它本身還實現了一套JS Parser,擁有一套代碼生成系統,等因而構建了一個完整的編譯工具鏈。Babili則是基於BABEL的插件實現的。框架
由此咱們能夠從一直使用的壓縮器中感覺到編譯時優化是怎麼樣的一個做用過程。函數
早先的代碼維護是很是不方便的,因此就出現一些打包工具,倡導開發者使用模塊,使得代碼可以更好的維護。可是另外一個問題出現了,打包後代碼變得難以壓縮。這是由於早期的打包工具每個模塊都是包含在一個函數做用域內的,對於壓縮器來講每個做用域都是分離的,在進行優化的時候不少部分都沒法完成。工具
針對上面的問題Rollup這類的工具就誕生了,只要是使用了ES模塊,它就可讓全部的模塊都放在同一個做用域中,這樣壓縮器就有用武之地。
在使用模板引擎的時候,一般都會將模板直接寫在JavaScript裏面,模板字符串會被編譯成JavaScript代碼,這個過程通常都是在瀏覽器上進行的,可是這樣就會增長用戶的等待時間。
其實這個編譯的過程徹底能夠放在構建時進行,由此AOT和JIT出現了。JIT在構建時並不編譯而是直接將模板發送到瀏覽器裏,當須要使用的時候再進行編譯。AOT則是在構建的時候提早進行編譯。
Angular、Vue、Glimmer就是一個典型構建時編譯的例子,編寫的時候是模板而當編譯完成後發送出去的倒是JavaScript代碼。Angular使用AOT達成這一目標,Vue在使用Vue-loader時候默認就是這樣執行的。
在生成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源碼內這些用不到的部分去除掉,這樣就能夠更進一步的精簡代碼生成量。