淺談React + Webpack 構(gòu)建打包優(yōu)化
本文介紹了React + Webpack 構(gòu)建打包優(yōu)化,分享給大家,具體如下:
使用 babel-react-optimize 對 React 代碼進行優(yōu)化
檢查沒有使用的庫,去除 import 引用
按需打包所用的類庫,比如 lodash 、 echart 等
lodash 可以采用babel-plugin-lodash 進行優(yōu)化。
需要注意的是
在 babel-react-optimize 中使用了 babel-plugin-transform-react-remove-prop-types 這個插件。正常情況下,如果你在代碼中沒有引用到組件的 PropTypes ,則完全沒問題。如果你的組件用到了,那么使用該插件可能會導(dǎo)致問題。
具體見:
https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types#is-it-safe
Webpack 構(gòu)建打包優(yōu)化
Webpack 構(gòu)建打包存在的問題主要集中于下面兩個方面:
- Webpack 構(gòu)建速度慢
- Webpack 打包后的文件體積過大
Webpack 構(gòu)建速度慢
可以使用 Webpack.DDLPlugin , HappyPack 來提高構(gòu)建速度。具體參見小銘在 DMP DDLPlugin 的文檔。原文如下:
Webpack.DLLPlugin
添加一個 webpack.dll.config.js
主要是用到一個 DllPlugin 插件,把一些第三方的資源獨立打包,同時放到一個 manifest.json 配置文件中,
這樣在組件中更新后,就不會重新 build 這些第三方的資源,
- 同時獨立配置 dll/vendors.js 文件,提供給 webpack.dll.config.js
- 修改 package.json
在 scripts 中添加: "dll": "webpack --config webpack.dll.config.js --progress --colors ", 。
執(zhí)行 npm run dll 以后,會在 dll 目錄下生產(chǎn) 兩個文件 vendor-manifest.json ,vendor.dll.js
配置 webpack.dev.config.js 文件,加入一個 DllReferencePlugin 插件,并指定 vendor-manifest.json 文件
new webpack.DllReferencePlugin({
context: join(__dirname, 'src'),
manifest: require('./dll/vendor-manifest.json')
})
修改 html
<% if(htmlWebpackPlugin.options.NODE_ENV ==='development'){ %>
<script src="dll/vendor.dll.js"></script>
<% } %>
注意,需要在 htmlWebpackPlugin 插件中配置 NODE_ENV 參數(shù)
Happypack
通過多線程,緩存等方式提升 rebuild 效率 https://github.com/amireh/happypack
在 webpack.dev.config.js 中針對不同的資源創(chuàng)建多個 HappyPack, 比如 js 1 個,less 1 個,并設(shè)置好 id
new HappyPack({
id: 'js',
threadPool: happyThreadPool,
cache: true,
verbose: true,
loaders: ['babel-loader?babelrc&cacheDirectory=true'],
}),
new HappyPack({
id: 'less',
threadPool: happyThreadPool,
cache: true,
verbose: true,
loaders: ['css-loader', 'less-loader'],
})
在 module.rules 中配置 use 為 happypack/loader, 設(shè)置 id
{
test: /\.js$/,
use: [
'happypack/loader?id=js'
],
exclude: /node_modules/
}, {
test: /\.less$/,
loader: extractLess.extract({
use: ['happypack/loader?id=less'],
fallback: 'style-loader'
})
}
減少 Webpack 打包后的文件體積大小
首先需要對我們整個 bundle 進行分析,由哪些東西組成及各組成部分所占大小。
這里推薦 webpack-bundle-analyzer 。安裝后在 webpack.dev.config.js 中添加插件即可,就能在每次啟動后自動在網(wǎng)站打開分析結(jié)果,如下圖
plugins.push( new BundleAnalyzerPlugin());

除此之外,還可以將打包過程輸出成json文件
webpack --profile --json -> stats.json
然后到下面這兩個網(wǎng)站進行分析
通過上面的圖表分析可以清楚得看到,整個 bundle.js 的組成部分及對應(yīng)的大小。
解決 bundle.js 體積過大的解決思路如下:
- 生產(chǎn)環(huán)境啟用壓縮等插件,去除不必要插件
- 拆分業(yè)務(wù)代碼與第三方庫及公共模塊
- webpack 開啟 gzip 壓縮
- 按需加載
生產(chǎn)環(huán)境啟用壓縮等插件,去除不必要插件
確保在生產(chǎn)環(huán)境啟動 webpack.DefinePlugin 和 webpack.optimize.UglifyJsPlugin 。
const plugins = [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
drop_console: false //eslint-disable-line
}
})
]
拆分業(yè)務(wù)代碼與第三方庫及公共模塊
由于項目的業(yè)務(wù)代碼變更頻率很高,而第三方庫的代碼變化則相對沒有那么頻率。如果將業(yè)務(wù)代碼和第三庫打包到同一個 chunk 的話,在每次構(gòu)建的時候,哪怕業(yè)務(wù)代碼只改了一行,即使第三方庫的代碼沒有發(fā)生變化,會導(dǎo)致整個 chunk 的 hash 跟上一次不同。這不是我們想要的結(jié)果。我們想要的是,如果第三方庫的代碼沒有變化,那在構(gòu)建的時候也要保證對應(yīng)的 hash 沒有發(fā)生變化,從而能利用瀏覽器緩存,更好的提高頁面加載性能和縮短頁面加載時間。
因此可以將第三庫的代碼單獨拆分成 vendor chunk,與業(yè)務(wù)代碼分離。這樣就算業(yè)務(wù)代碼再怎么發(fā)生變化,只要第三方庫代碼沒有發(fā)生變化,對應(yīng)的 hash 就不變。
首先 entry 配置兩個 app 和 vendor 兩個chunk
entry: {
vendor: [path.join(__dirname, 'dll', 'vendors.js')],
app: [path.join(__dirname, 'src/index')]
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].[chunkhash:8].js'
},
其中 vendros.js 是自己定義的哪些第三方庫需要納入 vendor 中,如下:
require('babel-polyfill');
require('classnames');
require('intl');
require('isomorphic-fetch');
require('react');
require('react-dom');
require('immutable');
require('redux');
然后通過 CommonsChunkPlugin 拆分第三庫
plugins.push(
// 拆分第三方庫
new webpack.optimize.CommonsChunkPlugin({ name: 'vendor' }),
// 拆分 webpack 自身代碼
new webpack.optimize.CommonsChunkPlugin({
name: 'runtime',
minChunks: Infinity
})
);
上面的配置有兩個細節(jié)需要注意
- 使用 chunkhash 而不用 hash
- 單獨拆分 webpack 自身代碼
使用 chunkhash 而不用 hash
先來看看這二者有何區(qū)別:
- hash 是 build-specific ,任何一個文件的改動都會導(dǎo)致編譯的結(jié)果不同,適用于開發(fā)階段
- chunkhash 是 chunk-specific ,是根據(jù)每個 chunk 的內(nèi)容計算出的 hash,適用于生產(chǎn)
因此為了保證第三方庫不變的情況下,對應(yīng)的 vendor.js 的 hash 也要保持不變,我們再 output.filename 中采用了 chunkhash
單獨拆分 webpack 自身代碼
Webpack 有個已知問題:
webpack 自身的 boilerplate 和 manifest 代碼可能在每次編譯時都會變化。
這導(dǎo)致我們只是在 入口文件 改了一行代碼,但編譯出的 vendor 和 entry chunk 都變了,因為它們自身都包含這部分代碼。
這是不合理的,因為實際上我們的第三方庫的代碼沒變,vendor 不應(yīng)該在我們業(yè)務(wù)代碼變化時發(fā)生變化。
因此我們需要將 webpack 這部分代碼分離抽離
new webpack.optimize.CommonsChunkPlugin({
name: "runtime",
minChunks: Infinity
}),
其中的 name 只要不在 entry 即可,通常使用 "runtime" 或 "manifest" 。
另外一個參數(shù) minChunks 表示:在傳入公共chunk(commons chunk) 之前所需要包含的最少數(shù)量的 chunks。數(shù)量必須大于等于2,或者少于等于 chunks的數(shù)量,傳入 Infinity 會馬上生成 公共chunk,但里面沒有模塊。
更多關(guān)于 CommonChunkPlugin 可以查看 官方文檔
拆分公共資源
同 上面的拆分第三方庫一樣,拆分公共資源可以將公用的模塊單獨打出一個 chunk,你可以設(shè)置 minChunk 來選擇是共用多少次模塊才將它們抽離。配置如下:
new webpack.optimize.CommonsChunkPlugin({
name: 'common',
minChunks: 2,
}),
是否需要進行這一步優(yōu)化可以自行根據(jù)項目的業(yè)務(wù)復(fù)用度來判斷。
開啟 gzip
使用 CompressionPlugin 插件開啟 gzip 即可:
// 添加 gzip
new CompressionPlugin({
asset: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|html)$/,
threshold: 10240,
minRatio: 0.8
})
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
react?hooks?d3實現(xiàn)企查查股權(quán)穿透圖結(jié)構(gòu)圖效果詳解
這篇文章主要為大家介紹了react?hooks?d3實現(xiàn)企查查股權(quán)穿透圖結(jié)構(gòu)圖效果詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-01-01
React中使用Workbox進行預(yù)緩存的實現(xiàn)代碼
Workbox是Google Chrome團隊推出的一套 PWA 的解決方案,這套解決方案當中包含了核心庫和構(gòu)建工具,因此我們可以利用Workbox實現(xiàn)Service Worker的快速開發(fā),本文小編給大家介紹了React中使用Workbox進行預(yù)緩存的實現(xiàn),需要的朋友可以參考下2023-11-11
React-Router v6實現(xiàn)頁面級按鈕權(quán)限示例詳解
這篇文章主要介紹了使用 reac+reactRouter來實現(xiàn)頁面級的按鈕權(quán)限功能,這篇文章分三部分,實現(xiàn)思路、代碼實現(xiàn)、踩坑記錄,有需要的朋友可以借鑒參考下,希望能夠有所幫助2023-10-10
react開發(fā)中如何使用require.ensure加載es6風格的組件
本篇文章主要介紹了react開發(fā)中如何使用require.ensure加載es6風格的組件,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-05-05
React循環(huán)遍歷渲染數(shù)組和對象元素方式
這篇文章主要介紹了React循環(huán)遍歷渲染數(shù)組和對象元素方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-09-09
React tabIndex使非表單元素支持focus和blur事件
這篇文章主要為大家介紹了React使用tabIndex使非表單元素支持focus和blur事件實例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-11-11
React jsx轉(zhuǎn)換與createElement使用超詳細講解
這篇文章主要介紹了React jsx轉(zhuǎn)換與createElement使用,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習吧2022-11-11
react實現(xiàn)鼠標懸停在SVG地圖上某個區(qū)域時上方呈現(xiàn)柱形圖效果
這篇文章主要介紹了react實現(xiàn)鼠標懸停在SVG地圖上某個區(qū)域時,其上方呈現(xiàn)柱形圖,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2025-04-04

