webpack + react 優化:縮小js包體積
一,前言
學校這邊的專案剛組建好開發團隊,前一段時間都在考慮如何前後端分離,如何多人協作開發的問題,恰好上一週陪女朋友去承德寫生,能暫時放下工作和學校的事物,有了更多的思考時間。假期期間學習了webpack,並將前端程式碼進行了遷移,實現了前後端分離。
而最近上線的時候發現打包壓縮後的js包達到了477k,首屏渲染時間高達4s,首屏渲染時間超過1.5s都是不能忍的,於是開始嘗試研究一下webpack,畢竟只看了幾個小時就拿來用了。
劇透,劇透,後面優化到284k,首屏渲染1.5s-2s。
這個時候想起以前boss和我聊職業規劃的時候說過,“會用一項技術的人有很多,而出了問題懂得最大程度優化處理的人卻沒幾個”
,雖然他舉的例子是搜尋引擎優化,要高大上得多,但深入學習,積極對待的心態是一樣的。謝謝他的引導。
二,思路
前面囉嗦有點多,下面簡單說說這次優化的思路。要想解決問題,必先了解問題,我去看了打包後的js,發現了一些問題及優化點。
js確實混淆壓縮了,可是裡面含有大量的開源庫的copyright資訊,可以去掉。
(開源大牛們要相信我是尊重以及無敵崇拜你們的,為了效能暫時去掉這些資訊,後期會在產品上單開一個頁面說明自己用了哪些庫以及給出連結(Facebook和Instagram都這樣))
引入的React沒有切換到產品版本,React給出了下面的提示,良心!
Warning: It looks like you’re using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster. See
之前將css也打包進js裡面了,因為css和js並行載入,所以可以將css分離出來,因為js遠大於css,所以首屏渲染時間絕大部分只受js下載時間影響,看圖:
三,動手
①壓縮時去掉js所有註釋,包括copyright資訊。
在webpack.config.js檔案的plugins數組裡面新增及配置外掛即可。
關於uglify的更多配置,請點選這裡.
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false , // remove all comments
},
compress: {
warnings: false
}
})
從477k 縮小到了408k,go ahead.
②將React切換到產品環境,參考如下:
同樣在plugins裡面新增:
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
}),
這時候注意打包的時候要帶上node的環境設定,例如:
NODE_ENV=production webpack --config webpack.production.config.js --progress
從408k縮小到326k,還可以更進一步。
③分離css
先安裝webpack外掛:
npm install extract-text-webpack-plugin --save
在webpack配置檔案中使用外掛:
var ExtractTextPlugin = require("extract-text-webpack-plugin");
...
loaders:[
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
},
...
...
plugins: [
...
new ExtractTextPlugin("bundle.css")
]
最後326k = 284k(js) + 37.6k(css).
附上完整的webpage配置檔案:
var webpack = require('webpack');
var path = require('path');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: [
path.resolve(__dirname, 'app/main.jsx')
],
output: {
path: __dirname + '/server/public',
publicPath: '/',
filename: './bundle.js'
},
module: {
loaders:[
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
{
test: /\.less$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader")
},
{ test: /\.(jpg|png)$/, loader: "url" },
{ test: /\.js[x]?$/, include: path.resolve(__dirname, 'app'), exclude:/node_modules/,loader: 'babel-loader' },
]
},
resolve: {
extensions: ['', '.js', '.jsx'],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
output: {
comments: false,
},
compress: {
warnings: false
}
}),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
},
}),
new ExtractTextPlugin("bundle.css")
]
};
四,更進一步
1.5s-2s的首屏渲染時間還不理想,但學校的專案要求也不高,不過對自己的要求應該一如既往,後期會嘗試從下面幾個方向去優化,希望能有更多的實踐經驗和大家分享。
- 將js分離,不同頁面載入不同的js;
- 將React剝離出去,使用cdn;
- 既然用了React,可以嘗試後端渲染;
雖然還不完美,但是進步總是值得肯定的,一步步來吧。
2016-09-16更新
進一步優化: