首頁 >web前端 >js教程 >React 與Webpack建置打包優化實例詳解

React 與Webpack建置打包優化實例詳解

小云云
小云云原創
2018-01-24 09:57:191802瀏覽

本文主要介紹了淺談React + Webpack 建置打包優化,小編覺得蠻不錯的,現在分享給大家,也給大家做個參考。一起跟著小編過來看看吧,希望能幫助大家。

使用babel-react-optimize 對React 程式碼進行最佳化

檢查沒有使用的函式庫,去除import 參考

按需打包所使用的類函式庫,如lodash 、 echart 等

lodash 可以採用babel-plugin-lodash 來進行最佳化。

要注意的是

在 babel-react-optimize 中使用了 babel-plugin-transform-react-remove-prop-types 這個插件。正常情況下,如果你在程式碼中沒有引用到元件的 PropTypes ,則完全沒問題。如果你的元件用到了,那麼使用該插件可能會導致問題。

具體見:

https://github.com/oliviertassinari/babel-plugin-transform-react-remove-prop-types#is-it-safe

#Webpack 建置打包最佳化

Webpack 建置打包存在的問題主要集中於以下兩個面向:

  1. Webpack 建置速度慢

  2. Webpack 打包後的檔案體積過大

#Webpack 建置速度慢

可以使用Webpack.DDLPlugin , HappyPack 來提高建置速度。詳見小銘在 DMP DDLPlugin 的文件。原文如下:

Webpack.DLLPlugin

新增一個webpack.dll.config.js
主要用到一個DllPlugin 插件,把一些第三方的資源獨立打包,同時放到一個manifest.json 設定檔中,

這樣在元件中更新後,就不會重新build 這些第三方的資源,

  1. 同時獨立設定dll/vendors .js 文件,提供給webpack.dll.config.js

  2. 修改package.json

在scripts 中加入: "dll": "webpack --config webpack.dll.config.js --progress --colors ", 。

執行npm run dll 以後,會在dll 目錄下生產兩個文件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 ===&#39;development&#39;){ %>
 <script src="dll/vendor.dll.js"></script>
<% } %>

注意,需要在htmlWebpackPlugin 外掛程式中設定NODE_ENV 參數

Happypack

透過多線程,快取等方式提升rebuild 效率https://github.com/amireh/ happypack

在webpack.dev.config.js 中針對不同的資源創建多個HappyPack, 例如 1 個,less 1 個,並且設定好id


new HappyPack({
 id: &#39;js&#39;,
 threadPool: happyThreadPool,
 cache: true,
 verbose: true,
 loaders: [&#39;babel-loader?babelrc&cacheDirectory=true&#39;],
}),
new HappyPack({
 id: &#39;less&#39;,
 threadPool: happyThreadPool,
 cache: true,
 verbose: true,
 loaders: [&#39;css-loader&#39;, &#39;less-loader&#39;],
})

在module.rules 中設定use 為happypack/loader,設定 id


{
 test: /\.js$/,
 use: [
 &#39;happypack/loader?id=js&#39;
 ],
 exclude: /node_modules/
}, {
 test: /\.less$/,
 loader: extractLess.extract({
 use: [&#39;happypack/loader?id=less&#39;],
 fallback: &#39;style-loader&#39;
 })
}

減少Webpack 打包後的檔案體積大小

首先需要對我們整個bundle 進行分析,由哪些東西組成及各組成部分所佔大小。

這裡推薦 webpack-bundle-analyzer 。安裝後在webpack.dev.config.js 中加入外掛程式即可,就能在每次啟動後自動在網站開啟分析結果,如下圖


plugins.push( new BundleAnalyzerPlugin());

除此之外,還可以將打包過程輸出成json檔案


webpack --profile --json -> stats.json

然後到下面這兩個網站進行分析

  1. #webpack/analyse

  2. Webpack Chart

透過上面的圖表分析可以清楚得看到,整個bundle .js 的組成部分及對應的大小。

解決bundle.js 體積過大的解決想法如下:

  1. 生產環境啟用壓縮等插件,移除不必要插件

  2. 拆分業務代碼與第三方函式庫及公用模組

  3. webpack 開啟gzip 壓縮

  4. 按需載入

生產環境啟用壓縮等插件,移除不必要插件

確保在生產環境啟動webpack.DefinePlugin 和webpack.optimize.UglifyJsPlugin 。


const plugins = [
 new webpack.DefinePlugin({
  &#39;process.env.NODE_ENV&#39;: JSON.stringify(process.env.NODE_ENV || &#39;production&#39;)
 }),
  new webpack.optimize.UglifyJsPlugin({
  compress: {
   warnings: false,
   drop_console: false //eslint-disable-line
  }
  })   
]

拆分業務代碼與第三方函式庫及公共模組

由於專案的業務程式碼變更頻率很高,而第三方函式庫的程式碼變化則相對沒有那麼頻率。如果將業務程式碼和第三函式庫打包到同一個chunk 的話,在每次建置的時候,即使是商業程式碼只改了一行,即使第三方函式庫的程式碼沒有發生變化,會導致整個chunk 的hash 跟上一次不同。這不是我們想要的結果。我們想要的是,如果第三方函式庫的程式碼沒有變化,那麼在建置的時候也要保證對應的 hash 沒有發生變化,從而能利用瀏覽器緩存,更好的提高頁面載入效能和縮短頁面載入時間。

因此可以将第三库的代码单独拆分成 vendor chunk,与业务代码分离。这样就算业务代码再怎么发生变化,只要第三方库代码没有发生变化,对应的 hash 就不变。

首先 entry 配置两个 app 和 vendor 两个chunk


entry: {
 vendor: [path.join(__dirname, &#39;dll&#39;, &#39;vendors.js&#39;)],
 app: [path.join(__dirname, &#39;src/index&#39;)]
},
output: {
 path: path.resolve(__dirname, &#39;build&#39;),
 filename: &#39;[name].[chunkhash:8].js&#39;
},

其中 vendros.js 是自己定义的哪些第三方库需要纳入 vendor 中,如下:


require(&#39;babel-polyfill&#39;);
require(&#39;classnames&#39;);
require(&#39;intl&#39;);
require(&#39;isomorphic-fetch&#39;);
require(&#39;react&#39;);
require(&#39;react-dom&#39;);
require(&#39;immutable&#39;);
require(&#39;redux&#39;);

然后通过 CommonsChunkPlugin 拆分第三库


plugins.push(
 // 拆分第三方库
 new webpack.optimize.CommonsChunkPlugin({ name: &#39;vendor&#39; }),
 // 拆分 webpack 自身代码
 new webpack.optimize.CommonsChunkPlugin({
  name: &#39;runtime&#39;,
  minChunks: Infinity
 })
);

上面的配置有两个细节需要注意

  1. 使用 chunkhash 而不用 hash

  2. 单独拆分 webpack 自身代码

使用 chunkhash 而不用 hash

先来看看这二者有何区别:

  1. hash 是 build-specific ,任何一个文件的改动都会导致编译的结果不同,适用于开发阶段

  2. chunkhash 是 chunk-specific ,是根据每个 chunk 的内容计算出的 hash,适用于生产

因此为了保证第三方库不变的情况下,对应的 vendor.js 的 hash 也要保持不变,我们再 output.filename 中采用了 chunkhash

单独拆分 webpack 自身代码

Webpack 有个已知问题:

webpack 自身的 boilerplate 和 manifest 代码可能在每次编译时都会变化。

这导致我们只是在 入口文件 改了一行代码,但编译出的 vendor 和 entry chunk 都变了,因为它们自身都包含这部分代码。

这是不合理的,因为实际上我们的第三方库的代码没变,vendor 不应该在我们业务代码变化时发生变化。

因此我们需要将 webpack 这部分代码分离抽离


new webpack.optimize.CommonsChunkPlugin({
   name: "runtime",
   minChunks: Infinity
}),

其中的 name 只要不在 entry 即可,通常使用 "runtime" 或 "manifest" 。

另外一个参数 minChunks 表示:在传入公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks。数量必须大于等于2,或者少于等于 chunks的数量,传入 Infinity 会马上生成 公共chunk,但里面没有模块。

拆分公共资源

同 上面的拆分第三方库一样,拆分公共资源可以将公用的模块单独打出一个 chunk,你可以设置 minChunk 来选择是共用多少次模块才将它们抽离。配置如下:


new webpack.optimize.CommonsChunkPlugin({
 name: &#39;common&#39;,
 minChunks: 2,
}),

是否需要进行这一步优化可以自行根据项目的业务复用度来判断。

开启 gzip

使用 CompressionPlugin 插件开启 gzip 即可:


// 添加 gzip
new CompressionPlugin({
 asset: &#39;[path].gz[query]&#39;,
 algorithm: &#39;gzip&#39;,
 test: /\.(js|html)$/,
 threshold: 10240,
 minRatio: 0.8
})

大家学会了吗?赶紧动手尝试一下吧。

相关推荐:

parcel.js打包出错到选择nvm的全部过程解析

Parcel打包示例详解

webpack多入口文件页面打包详解


以上是React 與Webpack建置打包優化實例詳解的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn