webpack如何做性能优化
日益复杂的业务,越来越庞大的项目,用户体验要求也越来越高,性能问题是必须要考虑的。 今天主要考虑webpack中能做的性能优化有哪些
# 构建速度优化
# 使用新版本
这个是个万能策略,webpack新版本的发布,必定会带来性能提升。
# 优化搜索文件
Webpack 的打包范围很大程度上会影响它的性能。可以使用Webpack提供的配置项来缩小打包范围。排除 Webpack 不需要解析的模块,即使用 loader 的时候,在尽量少的模块中去使用。
例如,可以使用 include、exclude 等选项来控制哪些模块需要打包,哪些模块不需要打包。 这样可以减少不必要的文件的解析和编译,从而提高Webpack的性能。
module.exports = {
//...
module: {
rules: [
{
test: /\.js|jsx$/,
exclude: /node_modules/,
include: path.resolve(__dirname, '../src'),
use: ['babel-loader']
},
// ...
]
},
};
# 缩小文件检索范围
合理使用resolve alias(减少查找过程) extensions(给定文件扩展中搜索) modules(给定目录中搜索)优化文件检索范围;
module.exports = {
//...
resolve: {
// ...
alias: {
react: path.resolve(__dirname, './node_modules/react/dist/react.min.js'),
@alias: path.resolve(__dirname, '../src/alias'),
},
},
};
# 对匹配文件分析转化
使用module.noParse 指定不需要解析的文件,用来排除非模块化文件的解析 ;
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。
module.exports = {
//...
module: {
noParse: /jquery|lodash/,
},
};
# 通过DllPlugin避免重复编译第三方库
预先编译资源模块,在打包的时候,一般来说第三方模块是不会变化的,所以我们想只要在第一次打包的时候去打包一下第三方模块,并将第三方模块打包到一个特定的文件中, 当第二次 webpack 进行打包的时候,就不需要去 node_modules 中去引入第三方模块,而是直接使用我们第一次打包的第三方模块的文件就行。
具体用法如下:
// 配置文件目录 config 下新建一个 webpack.dll.js,此文件用于将我们的第三方包文件打包到 dll 文件夹中去:
// config/webpack.dll.js
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production', // 环境
entry: {
vendors: ['lodash'], // 将 lodash 打包到 vendors.js 下
},
output: {
filename: '[name].dll.js', // 输出的名字
path: path.resolve(__dirname, '../dll'), // 输出的文件目录
library: '[name]' // 将我们打包出来的文件以全部变量的形式暴露,可以在浏览器变量的名字进行访问
},
plugins: [
// 对生成的库文件进行分析,生成库文件与业务文件的映射关系,将结果放在 mainfest.json 文件中
new webpack.DllPlugin({
name: '[name]', // 和上面的 library 输出的名字要相同
path: path.resolve(__dirname, '../dll/[name].manifest.json'),
})
]
}
同时我们需要使用 webpack 自带的 DllReferencePlugin 插件对 mainfest.json 映射文件进行分析。
module.exports = {
plugins: [
new webpack.DllReferencePlugin({
manifest: require(path.resolve(__dirname, '../dll/vendors.dll.mainfest.json'))
}),
],
}
# 使用thread-loader开启多进程loader转换
webpack 官方推出的一个多进程方案,用来替代 HappyPack。 每次 webapck 解析一个模块,HappyPack 会将它及它的依赖分配给 worker 线程中。处理完成之后,再将处理好的资源返回给 HappyPack 的主进程,从而加快打包速度。
module.exports = {
//...
module: {
rules: [{
test: /\.jsx?$/,
use: [
{
loader: 'thread-loader',
options: {
workers: 3, // 开启几个 worker 进程来处理打包,默认是 os.cpus().length - 1
}
},
'babel-loader'
]
}]
},
};
# 优化输出代码
# 压缩资源
# js压缩
webpack4.0 默认是使用 terser-webpack-plugin 这个压缩插件,在此之前是使用 uglifyjs-webpack-plugin, 区别是uglifyjs-webpack-plugin对 ES6 的压缩不是很好,同时我们可以开启 parallel 参数,使用多进程压缩,加快压缩。
// config/webpack.common.js
const TerserPlugin = require('terser-webpack-plugin');
const commonConfig = {
// ...
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: 4, // 开启几个进程来处理压缩,默认是 os.cpus().length - 1
}),
],
},
// ...
}
# css压缩
我们可以借助 optimize-css-assets-webpack-plugin 插件来压缩 css,其默认使用的压缩引擎是 cssnano。
使用 PurgeCSS 来完成对无用 css 的擦除,它需要和 mini-css-extract-plugin 配合使用。
# 图片压缩
我们就可以借助 image-webpack-loader 帮助我们来实现。它是基于 imagemin 这个 Node 库来实现图片压缩的。
# Tree Shaking去除无用代码
使用 ES6 Modules 语法,以保证 Tree-Shaking 起作用 ;因为 tree-shaking 只对 ES6 Modules 静态引入生效,对于类似于 CommonJs 的动态引入方式是无效的
# 代码分割,按需加载
Webpack提供了Code Splitting机制,可以将代码拆分成多个包,以便更快地加载和处理代码。可以使用以下方法开启Code Splitting: 使用SplitChunksPlugin将公共的代码提取成一个独立的文件,避免代码重复加载。
// 使用 SplitChunksPlugin 将公共代码提取成一个单独的文件
module.exports = {
optimization: {
splitChunks: {
chunks: 'all' // 可取 all,async 和 initial,默认值async
}
}
};
# 分离第三方库,使用cdn加载资源
module.exports = {
//...
externals: {
lodash: '_'
}
};
需要注意的是,如果你使用externals,则必须确保在打包后能够正确地获取这些模块。可以配合html-webpack-externals-plugin来自动插入script标签
# gzip压缩
const CompressionPlugin = require('compression-webpack-plugin');
module.exports = {
plugins: [
new CompressionPlugin(),
],
};
# 使用动态导入来延迟加载代码
import(/* webpackChunkName: "my-chunk" */ './my-module').then((module) => {
// do something with module
});
# 合理配置 chunk 的哈希值来利用缓存
在生产环境打包,一定要配置文件的 hash,这样有助于浏览器缓存我们的文件,当我们的代码文件没变化的时候,用户就只需要读取浏览器缓存的文件即可。 一般来说
- javascript 文件使用 [chunkhash]
- css 文件使用 [contenthash]
- 其他资源(例如图片、字体等)使用 [hash]
# 合理使用 sourceMap
生成 sourceMap 的时候,如果信息越详细,打包速度就会越慢