webpack5性能优化篇
优化构建速度
优化babel-loader
为了让我们写的ES6+
语法的 JS 代码能够正常运行在低版本的浏览器中,通常需要将其转换为ES5
语法,这时我们需要用到babel-loader
。但直接使用babel-loader
可能会导致webpack
构建速度慢,所以我们从以下两点进行优化:
- 转译尽可能少的文件
- 开启转译缓存
配置如下:
module: {
rules: [
{
test: /\.js$/,
// 通过 cacheDirectory 开启缓存,
// 缓存目录为 node_modules/.cache/babel-loader
use: ["babel-loader?cacheDirectory"],
// 排除范围,include 和 exclude 两者选一个即可
include: srcPath,
exclude: /node_modules/,
},
],
},
IgnorePlugin
例如我们在使用moment
依赖时,默认会引入所有语言的 JS 代码,如果直接使用,会导致打包后的代码体积比较大。这时我们可以使用IgnorePlugin
来忽略我们不需要引入的代码,使用方式如下:
plugins: [
// 忽略 moment 下的 /locale 目录
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
}),
],
这时候moment
默认使用语言英语,如果要使用别的语言,可以手动引入需要使用的语言包。
import moment from "moment";
import "moment/locale/zh-cn";
moment.locale("zh-cn");
noParse
如react.min.js
、jQuery
等已经进行模块化的文件,我们无需再次构建,可对其进行忽略处理,处理方式如下:
module: {
// min.js 一般已经模块化,无需我们再次处理
noParse: [/react\.min\.js/],
},
IgnorePlugin 对比 noParse IgnorePlugin 直接不引入,代码中没有。noParse 引入,但不打包。
happypack
JS 是单线程的,使用happypack
开启多进程打包,提高构建速度。
const HappyPack = require("happypack");
module: {
rules: [
{
test: /\.js$/,
// 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
use: ["happypack/loader?id=babel"],
// 排除范围,include 和 exclude 两者选一个即可
include: srcPath,
// exclude: /node_modules/,
},
],
},
plugins: [
// happy开启多进程打包
new HappyPack({
// 用唯一的标识符 id 来代表当前的 HappyPack 是用来处理一类特定的文件
id: "babel",
// 如何处理 .js 文件,用法和 Loader 配置中一样
loaders: ["babel-loader?cacheDirectory"],
}),
],
terser-webpack-plugin
该插件可以压缩 JS 代码体积,开启多进程压缩可提高构建速度,配置如下:
const TerserJSPlugin = require("terser-webpack-plugin");
optimization: {
// 压缩 js
minimizer: [
new TerserJSPlugin({
// 开启多进程压缩
parallel: true,
}),
],
}
关于开启多进程 项目较大,打包较慢,开启多进程能提高速度 项目较小,打包很快,开启多进程会降低速度(进程开销) 按需使用
热更新
自动刷新
与热更新
的区别:
- 自动刷新:整个网页全部刷新,速度较慢
- 自动刷新:整个网页全部刷新,状态会丢失
- 热更新:新代码生效,网页不刷新,状态不丢失
devServer: {
// 开启热更新
hot: true,
},
如需改动样式文件,热更新即可生效。 如需改动 js 文件,则需要进行如下改写:
// 开启热更新之后的代码逻辑
if (module.hot) {
// math.js中代码发生变化页面不会整体刷新
module.hot.accept("./math.js", () => {
// 热更新的回调函数
const sumRes = sum(10, 20);
console.log("热更新", sumRes);
});
}
优化代码体积
小图片 base64 编码
module: {
rules: [
// 图片 - 考虑 base64 编码的情况
{
test: /\.(png|jpg|jpeg|gif)$/,
use: {
loader: "url-loader",
options: {
// 小于 5kb 的图片用 base64 格式产出
// 否则,依然延用 file-loader 的形式,产出 url 格式
limit: 5 * 1024,
// 打包到 img 目录下
outputPath: "/img/",
// 设置图片的 cdn 地址(也可以统一在外面的 output 中设置,那将作用于所有静态资源)
// publicPath: 'http://cdn.abc.com'
},
},
},
],
},
bundle 加 hash
output: {
filename: "[name].[contenthash:8].js", // name 即多入口时 entry 的 key
},
提取公共代码
optimization: {
// 分割代码块
splitChunks: {
chunks: "all",
/**
* initial 入口chunk,对于异步导入的文件不处理
* async 异步chunk,只对异步导入的文件处理
* all 全部chunk
*/
// 缓存分组
cacheGroups: {
// 第三方模块
vendor: {
name: "vendor", // chunk 名称
priority: 1, // 权限更高,优先抽离,重要!!!
test: /node_modules/,
minSize: 0, // 大小限制
minChunks: 1, // 最少复用过几次
},
// 公共的模块
common: {
name: "common", // chunk 名称
priority: 0, // 优先级
minSize: 0, // 公共模块的大小限制
minChunks: 2, // 公共模块最少复用过几次
},
},
},
},
IgnorePlugin
使用方式在优化构建速度中已经说明了,使用IgnorePlugin
也可以减少构建后代码体积
使用 CDN 加速
所有的静态文件都会加上 CDN 的前缀,打包后需要将静态文件放到 CDN 上
output: {
publicPath: "http://cdn.abc.com", // 修改所有静态文件 url 的前缀(如 cdn 域名)
},
使用 production
- 能够自动开启代码压缩
- Vue React 等会自动删掉调试代码(如开发环境的 warning)
- 启动 Tree-Shaking(ES6 Module 才能让 tree-shaking 生效)
Scope Hosting
未开启时,一个 js 文件会生成一个函数,开启后会将多个 js 文件相关代码合并到一个函数中。
开启后优点:
- 代码体积更小
- 创建函数作用域更少
- 代码可读性更好
resolve: {
// 针对 npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ["jsnext:main", "browser", "main"],
},
plugins: [
// 开启 scope hosting
new webpack.optimize.ModuleConcatenationPlugin(),
];
转载自:https://juejin.cn/post/7230823928758796325