最近在系统整理知识点,现将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, '../') }) ] ....