【前端構建】WebPack實例與前端性能優化


計划把微信的文章也搬一份上來。

這篇主要介紹一下我在玩Webpack過程中的心得。通過實例介紹WebPack的安裝,插件使用及加載策略。感受構建工具給前端優化工作帶來的便利。

壹 | Fisrt

曾幾何時,我們是如上圖的方式引入JS資源的,相信現在很少遇見了。近年來Web前端開發領域朝着規范開發的方向演進。體現在以下兩點:

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

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

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

所以,前端這么好玩,如果還有項目沒有前后端分離的話,真的是守舊過頭了。

 

主流構建工具

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

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

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

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

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的構建過程中思考的一些問題(這些問題基本會在每個項目中遇到),讓這些插件逐一登場。

一、文件過大

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

 

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

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

 

二、如何緩存

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

  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的。

 

三、自動生成頁面

文件名帶上版本號后,每一次文件變化,都需要Html文件里手動修改引用的文件名,這種重復工作很瑣碎且容易出錯。

使用 HtmlWebpackPlugin 和 ExtractTextPlugin 插件可以解決此問題。

  • 生成帶JS的頁面

  • 生成帶css的頁面

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

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

 

肆 | Fourth

關於同步加載和異步加載

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

 

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

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

  • 同步加載的寫法,如:

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

  • 異步加載的寫法,如:

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

 

結語

以上是WebPack構建工具比較好的實踐,可見,要用好還是很考驗前端性能優化的功力的,比較什么時候同步,什么時候異步,如果做緩存等等。

如果覺得文章有用,順手點擊下方的推薦 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM