webpack實例與前端性能優化

壹 | Fisrt

曾幾什麼時候,咱們是如上圖的方式引入JS資源的,相信如今不多碰見了。近年來Web前端開發領域朝着規範開發的方向演進。體如今如下兩點:css

  1. MVC研發構架。多多益處(邏輯清晰,程序注重數據與表現分離,可讀性強,利於規避和排查問題...)前端

  2. 構建工具層出不窮。多多益處(提高團隊協做,以及工程運維,避免人工處理瑣碎而重複的工做)react

    • 模塊化開發
    • 將前端性能優化理論落地,代碼壓縮,合併,緩存控制,提取公共代碼等
    • 其餘的還包括好比你能夠用ES 6 或CoffeeScript寫源碼,而後構建出瀏覽器支持的ES5

因此,前端這麼好玩,若是還有項目沒有先後端分離的話,真的是守舊過頭了。jquery

 

主流構建工具webpack

市面上有許多構建工具,包括Grunt、Gulp、browserify等,這些和WebPack都是打包工具。但WebPack同時也具有如下特色:git

  1. 相比Grunt,WebPack除了具有豐富的插件外,同時帶有一套加載(Loader)系統。使它支持多種規範的加載方式,包括ES六、CommonJS、AMD等方式,這是Grunt、Gulp所不具有的。github

  2. 從代碼混淆的角度來看,WebPack更加的極致web

  3. 代碼分片爲處理單元(而不是文件),使得文件的分片更爲靈活。npm

P.S.此處只作簡單的比較,不論孰優孰劣。其實工具都能知足需求,關鍵是看怎麼用,工具的使用背後是對前端性能優化的理解程度。編程

貳 | Second 

WebPack安裝與使用

WebPack運行在 NodeJS之下,而且它及其插件都是使用NPM(NodeJS的包管理工具)管理。

  1. 安裝Node及NPM。到NodeJS官網安裝包,安裝便可

  2. 全局安裝WebPack。聯網狀況下,執行命令行 $npm install webpack -g 便可。 

此至便可使用WebPack了,到WebPack官網去按着Get start(http://webpack.github.io/docs/tutorials/getting-started/)的步驟來,感覺一個最簡單的構建過程。 

然而要把WebPack用好,只是跑起來是遠遠不夠的。

 

叄 | Third 

WebPack插件

花較大篇幅介紹插件的使用,如下經過在一個DemoApp的構建過程當中思考的一些問題(這些問題基本會在每一個項目中遇到),讓這些插件逐一登場。

1、文件過大

DemoApp最初的構建結果以下:

這裏生成了一個topic.xxx.js,這個文件原本很小,估計只有10Kb左右,但構建的結果竟然快1Mb了。在3G網絡(750Kb/s)下的加載瀑布流以下圖:

這張圖(體現前端文件加載過程)曝露了幾個問題:

  1. 上面箭頭所指的很藍色柱子,說明了大部分時間消耗在加載topic.xxxx.js上。

  2. 全部JS文件相關的柱子是一根結束了另外一根纔開始,說明不合理的文件合併策略,致使文件串行加載。

  3. 結果就是如底部的箭頭所看到的,頁面的加載時間太長了(3G網絡,10+秒)。

觀察構建的文件,發現原來構建工具把React、jQuery等代碼庫合併到了topic.xxxx.js,形成此文件過大。若是再加一個activity模塊呢?很明顯,activity.xxx.js獲得相似的結果,都太大了,而且React、jQuery等代碼庫重複被合併到activity和topic裏,以下圖。若是再加模塊也會獲得一樣的結果,模塊越多重複加載的狀況越嚴重

可見,提取公共代碼,狀況能夠獲得改善,另外,壓縮代碼無疑是可使文件變小的。

1. 提取React、jQuery等庫文件。它們不多變化,而且處處被複用,應該被提取出來,而且獲得長時間的緩存。

此處使用插件:WebPack.optimize.CommonsChunkPlugin(WebPack內建插件)

 

 2. 代碼壓縮。React由700+ Kb壓縮成100+ Kb

此處使用插件:WebPack.optimize.UglifyJsPlugin (WebPack內建插件)

處理後topic.xxx.js和activity.xxx.js都很小了,而且多了jquery.xxx.js和react.xxx.js

 

再看看文件加載的瀑布流,柱子所佔比例短了,同時資源並行加載。

到此爲止,這個問題算比較好地解決了,但還不夠,隨着項目愈來愈大,還有一個重要因素會致使文件很大。這部份內容放到本文的最後介紹。

 

2、如何緩存

緩存控制要作到兩件事情,提到緩存命中率

  1. 對於沒有修改的文件,從緩存中獲取文件

  2. 對於已經修改的文件,不要從緩存中獲取

圍繞這兩點,演繹出了不少方案,此處列兩種:

  • 不處理,等待用戶瀏覽器緩存過時,自動更新。這是最偷懶的,命中率低一些,同時可能會出現部分文件沒有更新,致使報錯的狀況。

  • Http頭對文件設置很大的max-age,例如1年。同時,給每一個文件命名上帶上該文件的版本號,例如把文件的hash值作爲版本號,topic. ef8bed6c.js。便是讓文件很長時間不過時。

    • 當文件沒有更新時,使用緩存的文件天然不會出錯;

    • 當文件已經有更新時,其hash值必然改變,此時文件名變了,天然不存在此文件的緩存,因而瀏覽器會去加載最新的文件。

從上面的截圖能夠看出來,經過WebPack是能夠很輕鬆作到第二點的——只須要給文件名配置上[chunkhash:8]便可,其中8是指hash長度爲8,默認是16。

P.S.這樣的處理效果已經很好了,但一樣有劣處,即瀏覽器給這種緩存方式的緩存容量太少了,只有12Mb,且不分Host。因此更極致的作法是以文件名爲Key,文件內容爲value,緩存在localStorage裏,命中則從緩存中取,不命中則去服務器取,雖然緩存容量也只有5Mb,可是每一個Host是獨享這5Mb的。

 

3、自動生成頁面

文件名帶上版本號後,每一次文件變化,都須要Html文件裏手動修改引用的文件名,這種重複工做很瑣碎且容易出錯。

使用 HtmlWebpackPlugin 和 ExtractTextPlugin 插件能夠解決此問題。

  • 生成帶JS的頁面

  • 生成帶css的頁面

  new ExtractTextPlugin("comm.[contenthash:9].css")

  插件介紹到此爲止,然而,還有一個關於同步加載和異步加載的問題,不然入口文件仍是會很臃腫。

 

肆 | Fourth

關於同步加載和異步加載

使用WebPack打包,最爽的事情莫過於能夠像服務器編程那樣直接require文件,看起來是同步地從服務器上取得文件直接就使用了。以下面的代碼同樣,沒有任何異步邏輯,代碼很乾淨。

 

然而,這種爽是有代價的,對於直接require模塊,WebPack的作法是把依賴的文件都打包在一塊兒,形成文件很臃腫。

因此在寫代碼的時候要注意適度同步加載,同步的代碼會被合成而且打包在一塊兒;異步加載的代碼會被分片成一個個chunk,在須要該模塊時再加載,即按需加載,這個度是要開發者本身把握的,同步加載過多代碼會形成文件過大影響加載速度,異步過多則文件太碎,形成過多的Http請求,一樣影響加載速度。

  • 同步加載的寫法,如:

     var TopicItem = require('../topic/topicitem');

  • 異步加載的寫法,如:

一個原則是:首屏須要的同步加載,首屏事後才須要的則按需加載(異步)

 

結語

以上是WebPack構建工具比較好的實踐,可見,要用好仍是很考驗前端性能優化的功力的,比較何時同步,何時異步,若是作緩存等等。

相關文章
相關標籤/搜索