同步自個人博客javascript
開門見山,因爲咱們項目的前端代碼只有一個bundle
,全部代碼都在一個js文件裏,隨着功能不斷的堆疊,體積已經到沒法忍受的地步了(gzip後即將突破300k),致使首屏的時間不停的漲啊漲,最近一週富裕了一點人力趕忙作一次優化,暫時緩住了勢頭。css
react+webapck的優化文章如今一搜一大把,此次只說說個人技術方案,以及我是如何分析和優化的。前端
首先,我先說下,gzip
,cdn
等等前端優化手段咱們都是有的,此次主要是爲了解決bundle
過大的問題。java
咱們項目的整體架構很簡單易懂,react
全家桶:react
+redux
,哈哈。共有三個系統,每一個系統有本身單獨的工程。因爲是Hybrid
應用,爲了儘量貼合APP
內的切頁效果,每一個工程又都是採用的是單頁+多頁的形式。node
因爲系統多+單頁多頁混合,致使咱們的路由比較混亂,原本打算上react-router
進行一次大的改版,可是時間不夠充裕,綜合時間,開發成本角度來看,我定了一個簡單並能夠快速實施的方案:react
bundle
。好比react
,redux
,redux-thunk
以及一些polyfill
,由於這些都是長時間不會變更的代碼,因此能夠最大程度的命中緩存,而且每次發佈不須要從新下載這部分代碼,在項目中就用externals
的方案去引用這些代碼。code split
,每一個工程按照多頁的路由作代碼切割,每一個多頁路由都有本身的bundle
。這個很簡單,使用webpack
的requre.ensure
就能夠了webpack
addPage(cb){
require.ensure([], function () {
cb({
Page1: require('../../pages/Page1'),
Page2: require('../../pages/Page2')
})
});
}複製代碼
這裏Page1
和Page2
的代碼都是異步加載的,具體的部分涉及到路由的設計,咱們目前的方案很是的簡單和隨便,就不細說了。我也看了react-router
的解決方案,以爲寫起來複雜了一些,後續可能會在尋找更好的方案或者本身擼一個。git
這裏須要注意,雖然咱們的js
代碼作了拆分,css
文件仍是但願打包成一個,因此須要給ExtractTextPlugin
增長allChunks
的配置。github
new options.ExtractTextPlugin('[name]@[contenthash].css', {allChunks: true})複製代碼
我將react
,redux
等等公用的代碼打包成一個lib.js
,而後暴露在全局變量上。每一個工程裏都會先去引用這個lib.js
,在webpack
的配置裏就只須要配置上externals
就能夠了web
咱們還用了一些其餘插件來儘量的優化體積
UglifyJsPlugin
很少說了,代碼混淆壓縮DedupePlugin
消除重複引用的模塊,好像webpack2
已內置,使用webpack2
的能夠忽略OccurrenceOrderPlugin
讓依賴次數多的模塊靠前分到更小的id來達到輸出更多的代碼CommonsChunkPlugin
這個咱們沒有用,可是你們能夠去看看,對於多頁應用它能夠幫助你將一些公共代碼打包在作代碼拆分的時候我曾遇到過一個問題,如何確認個人代碼已是最優的了,如何確認我沒法繼續優化了?這就須要咱們去查看,這個bundle
究竟打包了哪些代碼,是否這些都是咱們須要的。
首先我推薦一個網址,這裏介紹了不少webpack
優化的工具。
我本身推薦兩個bundle
體積的可視化分析工具
具體如何使用我就不介紹了,它們的文檔寫的很清楚你們能夠去文檔上看,他們均可以很清楚的看到每一個bundle
分別打包了哪些代碼,哪些佔據了最大的體積,也能夠觀察哪些代碼實際上是無用的能夠優化掉的。
這裏我還遇到過一個問題,好比我在detail.chunk.js
裏發現引入了一個loading
組件,可是我映象裏詳情頁並無引入loading
組件呀,這時候就須要去尋找loading
是被誰依賴了。以前我都是用webstorm的find usages
一點點的去看引用關係,其實能夠用webpack
提供的一個官方工具來作這件事。
首先,你須要這麼啓動webpack
webpack --profile --json > stats.json複製代碼
此時會生成一個stats.json
文件,以後在官方分析工具裏上傳文件便可對你的bundle進行分析。
這裏我用官方的例子簡單說下
上傳你的json
文件,長傳後會看到這麼一個界面,會簡單描述你的webpack
的版本,有多少modules
,多少chunks
等等
點擊chunks
,能夠看到全部chunks
的描述,左邊是chunks
的id,而後有namse
,有多少modules
,大小,引用它的chunks
是誰、即parents
,假如咱們須要分析id
爲1的chunk
,只須要點擊左邊的id
這裏你能夠看到更詳細的信息,這裏最重要的是兩個,reasons
是引用這個chunks
的模塊,modules
是這個chunks
所引用的modules
這裏你發現有一個模塊不是你想要的modules
,你只須要點擊這個模塊的id,再去查看reasons
就能夠看到這個模塊是被誰引入的
webpack吐槽的常態 —— 打包慢,這裏說一下咱們這邊作過的優化。
將resolve.modules
配置爲node_modules
,像使用 impot _ from "lodash"
這種時webpack遍歷向上遞歸查到node_modules
,但一般只有一個node_modules
,爲了減小能夠直接寫明node_modules
的地址
loader
也能夠設置須要生效的目錄地址
好比babel
的loader
能夠只對src目錄裏的代碼進行編譯,忽略龐大的node_modules
{
test:/\.js$/,
loader:'babel-oader',
include:path.resolve(__dirname,'src')
}複製代碼
發佈到npm的庫大多包含兩個目錄,一個是放cmd模塊化的lib目錄,一個是全部文件合併成的dist目錄,多數入口文件是指向lib的。默認狀況下webpack會去讀lib目錄下的入口文件再去遞歸加載其餘以來的文件,這個過程很是耗時,alias
可讓webpack直接使用dist目錄的總體文件減小遞歸
有些庫是自成一體,不須要依賴別的庫的,webpack無需解析他們的依賴,能夠配置這些文件脫離Webpack解析。
happyPack的文檔也寫的很好,就不復制粘貼了,你們能夠自行去閱讀文檔,簡單地說,它主要是利用多進程+緩存使得build
更快,這大幅減小了咱們在編譯機上編譯的時間。
先說說優化完後的結果,因爲react
的體積過大,lib
就有60k+,基本已經不能繼續優化了,加上咱們的路由設計的很很差,首屏的bundle依然有70k+,總的來講,首屏從280k下降到140k左右。
可是,根據監控的效果來看,頁面js下載的整體時間和白屏時間都只下降了30%左右,這並不符合個人心理預期,想了想除了http請求變多之外並無別的反作用,後續會繼續深刻的分析一下爲何優化的效果沒達到預期。