最近在系統整理知識點,現將Webpack的一些重要知識點羅列出來,方便快速查閱。
爲了使用tree shaking
,須要知足如下條件:javascript
import
和export
)package.json
文件中,添加sideEffects
入口這種方式是經過package.json
的sideEffects
屬性來實現的。css
{ "sodeEffects": false }
「反作用」的定義是,在導入時會執行特殊行爲的代碼,而不是僅僅暴露一個export
或多個export
。舉例說明,例如polyfill
,它影響全局做用域,而且一般不提供export
。
注意,任何導入的文件都會受到tree shaking
的影響。這意味着,若是在項目中使用相似css-loader
並導入CSS
文件,則須要將其添加到 side effect 列表中,以避免在生產模式中無心中將它刪除:java
{ "sideEffects": ['*.css'] }
從 webpack 4 開始,也能夠經過 "mode" 配置選項輕鬆切換到壓縮輸出,只需設置爲 "production"。
也能夠在命令行接口中使用--optimize-minimize
標記,來使用UglifyJSPlugin
。node
code splitting
的必要性webpack
code splitting
,打包後單文件提交較大,加載時長較長,影響用戶體驗code splitting
,常常修改業務代碼,從新打包後,瀏覽器不能進行緩存,致使性能較差,影響用戶體驗code splitting
的配置import _ from 'lodash';
webpack.common.js
配置以下:git
.... optimization: { splitChunks: { chunks: 'all' } } ....
配置後,會將公用類庫進行打包,生成一個vendors~main.js
文件。github
function getComponent() { return import('lodash').then(({ default: _ }) => { var element = document.createElement('div'); element.innerHTML = _.join(['Clear', 'love'], ''); return element; }) } getComponent().then(element => { document.body.appendChild(element); })
magic comment
)修改打包動態組件名稱@babel/plugin-syntax-dynamic-import
支持動態引入插件在.babelrc
中引用該插件web
.... plugins: ['@babel/plugin-syntax-dynamic-import'] ....
function getComponent() { return import(/* webpackChunkName:"lodash" */'lodash').then(({ default: _ }) => { var element = document.createElement('div'); element.innerHTML = _.join(['Clear', 'love'], ''); return element; }) } getComponent().then(element => { document.body.appendChild(element); })
關鍵是註釋:webpackChunkName: "lodash".
。打包後的文件名爲vendors~lodash.js
。
若想打包事後的文件名不帶vendors~
前綴,能夠修改webpack.common.js
中optimization
配置項:npm
.... optimization: { splitChunks: { chunks: "all", cacheGroups: { venders: false, default: false } } } ....
splitChunks: { chunks: 'async', // all async initial 是否對異步代碼進行的代碼分割 minSize: 30000, // 引入模塊大於30kb才進行代碼分割 maxSize: 0, // 引入模塊大於Xkb時,嘗試對引入模塊二次拆分引入 minChunks: 1, // 引入模塊至被使用X次後才進行代碼分割 maxAsyncRequests: 5, // maxInitialRequests: 3, automaticNameDelimiter: '~', name: true, cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, priority: -10, // 優先級 filename: 'vendors.js' // 打包文件名稱 }, default: { minChunks: 2, priority: -20, reuseExistingChunk: true // 是否複用已打包代碼 } } } }
function getComponent() { return import(/* webpackChunkName:"lodash" */'lodash').then(({ default: _ }) => { var element = document.createElement('div'); element.innerHTML = _.join(['Clear', 'love'], ''); return element; }) } document.addEventListener('click', () => { /* 當點擊時才加載lodash */ getComponent().then(element => { document.body.addChild(element); }) })
頁面初始化時,不會加載lodash
。當點擊頁面時才加載。import
引入動態組件實現的Lazy Loading
,其實跟Webpack
沒什麼關係。import
是ES6
的語法標準。而Webpack
藉助babel-profill
能識別該語法。json
每一個打包的js
文件都是一個chunk
webpack analyse
進行打包分析在package.json
的scripts
項中進行配置:
.... scripts: { "dev-build": "webpack --profile --json > stats.json --config ./build/webpack.dev.js" } ....
打包後會生成stats.json
,而後上傳該文件至webpack/analyse進行分析
Preload/Prefetch
document.addEventListener('click', () => { import(/* webpackPrefetch: true */ 'lodash').then(() => { .... }) })
Preload
和Prefetch
的區別:
preloaded chunk
與主模塊並行加載,而prefetched chunk
是主模塊加載完後再加載preloaded chunk
具備中等優先級,能夠當即下載。而prefetched chunk
是在瀏覽器空閒時下載。具體能夠參考prefetching/preloading-modules
若沒有進行css
的代碼分割,經過import
方式引入的樣式文件,將會被看成普通的模塊打包到.js
文件中。
若須要對css
進行代碼分割,須要藉助mini-css-extract-plugin
插件實現,具體以下:
// webpack.prod.js const MiniCssExtractPlugin = require("mini-css-extract-plugin") .... module: [{ test: /\.scss$/, use: [ MiniCssExtractPlugin.loader, { loder: 'css-loader', options: { importLoaders: 2 } }, 'saas-loader', 'postcss-loaerd' ] }, { test: /\.css$/, use: [ MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader' ] }], plugins: [ new MiniCssExtractPlugin({ filename: '[name].css', // 入口文件中直接引入css匹配該規則 chunkFilename: '[name].chunk.css' // 非入口文件中引入或嵌套引入匹配匹配該規則 }) ] ....
若須要對引入css
進行合併、壓縮,能夠藉助optimize-css-assets-webpack-plugin
。,具體配置以下:
// webpack.prod.js const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin") .... optimization: { minimizer: [new OptimizeCSSAssetsPlugin({})] } ....
若以前有配置過tree shaking
,則須要對如下文件進行修改:
webpack.common.js
optimization: { usedExports: true }
package.json
"sideEffects": [ "*.css" ]
webpack
實現瀏覽器緩存,主要是藉助配置output
中的contenthash
來實現的。
// webpack.prod.js .... output: { filename: '[name].[contenthash].js', chunkFilename: '[name].[contenthash].js' } ....
舊版webpack
進行打包時,雖然文件沒有進行任何修改,但打包後生成的contenthash
仍是會改變,這時須要再進行一些配置。
// webpack.common.js .... optimization: { runtimeChunk: { name: 'runtime' } } ....
使用最新穩定版本的webpack
、node
、npm
等,較新的版本更夠創建更高效的模塊樹以及提升解析速度。
將loaders
應用於最少數的必要模塊中,而不是:
// webpack.common.js module: { rules: [ { test: /\.jsx?$/, use: ['babel-loader'] } ] }
使用include
字段僅將loader
模塊應用在實際須要用其轉換的位置:
// webpack.common.js module: { rules: [ { test: /\.jsx?$/, include: path.resolve(__dirname, '../src'), use: ['babel-loader'] } ] }
減小編譯的總體大小,以提升構建性能。儘可能保持chunks
小巧。
CommonsChunksPlugin
async
模式使用CommonsChunksPlugin
thread-loader
能夠將很是耗性能的loaders轉存到worker pool
中。<br/>
不要使用太多的 workers ,由於 Node.js 的 runtime 和 loader 有必定的啓動開銷。最小化 workers 和主進程間的模塊傳輸。進程間通信(IPC)是很是消耗資源的。
對於一些性能開銷較大的loader
以前能夠添加cache-loader
,啓用持久化緩存。
使用package.json
中的postinstall
清楚緩存目錄。
使用DllPlugin
將更新不頻繁的代碼進行單獨編譯。這將改善引用程序的編譯速度。即便它增長了構建過程的複雜度。
如下幾步能夠提升解析速度:
resolve.modules
、resolve.extensions
、resolve.mainFiles
、resolve.desciriptionsFiles
中類目的數量,由於它們會增長文件系統的調用次數。symlinks
,能夠設置resolve.symlinks: false
plugins
,而且沒有指定context
信息,能夠設置resolve.cacheWithContext: false
如下幾個實用的工具經過在內存中進行代碼的編譯和資源的提供,但並不寫入磁盤來提升性能:
webpack-dev-server
webpack-hot-middleware
webpack-dev-middleware
須要注意在不一樣的devtool
的設置,會致使不一樣的性能差別。
eval
具備最好的性能,但不能幫你轉義代碼cheap-source-map
選擇來提升性能eval-source-map
配置進行增量編譯 在大多數狀況下,cheap-module-eval-source-map
是最好的選擇。
某些實用工具,plugins
和loaders
都只能在構建生產環境時才使用。例如,在開發時使用UglifyJsPlugin
來壓縮和修改代碼是沒有意義的。如下這些工具在開發中一般被排除在外:
UglifyJsPlugin
ExtractTextPlugin
[hash]/[chunkhash]
AggressiveSplittingPlugin
AggressiveMergingPlugin
ModuleConcatenationPlugin
webpack
只會在文件系統中生成已更新的chunk
。應當在生成入口chunk
時,儘可能減小入口chunk
的體積,以提升性能。
不要爲了很是小的性能增益,犧牲了你應用程序的質量!!請注意,在大多數狀況下優化代碼質量,比構建性能更重要。
當進行多個編譯時,如下工具能夠幫助到你:
parallel-webpack
: 它容許編譯工做在woker
池中進行。cache-loader
: 緩存能夠在多個編譯之間共享。項目中的preset/plugins
數量最小化
fork-ts-checker-webpack-plugin
進行類型檢查loaders
時跳過類型檢查ts-loader
時,設置happyPackMode: true
以及 transpileOnly: true
node-sass
中有個來自Node.js
線程池的阻塞線程的bug。當使用thread-loader
時,須要設置workParallelJobs: 2
CleanWebpackPlugin
根路徑在webpack.config.js
配置中,須要對plugins
中的CleanWebpackPlugin
的根路徑進行修改,能夠經過配置root
參數。
.... plugins: [ new CleanWebpackPlugin(['dist'], { root: path.resolve(__dirname, '../') }) ] ....