webpack优化
工具插件
耗时指标
npm i speed-measure-webpack-plugin -D
const SpeedMeasureWebpackPlugin = require("speed-measure-webpack-plugin");
const smw = new SpeedMeasureWebpackPlugin();
module.exports = smw.wrap({
mode: "development"
......
});
模块占比
npm i webpack-bundle-analyzer -D
- 会在打包后获取到本次打包中每个模块的占比,然后生成页面,自动打开
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");
...
plugins: [
new BundleAnalyzerPlugin(),
],
...
指定如何查找模块
resolve: {
extensions: [".js"],
alias: { bootstrap },
modules: ["scopeModules", "node_modules"],
mainFields: ["style", "main"],
mainFiles: ["index.js", "base.js"],
},
指定如何查找loader
- options等同于上面的resolve
- key为resolveLoader
resolveLoader: {
...
}
指定不解析的模块
- 通常我们需要webpack对模块进行分析,用来建立依赖树
- 但部分模块我们确定它没有依赖,就可以标识,省略这步
module: {
noParse: /loadash|jquery/,
noParse: (request) => {
return /loadash|jquery/.test(request);
}
},
指定某个库中不参与打包的文件
- 如:moment中会引入好多语言包
- 但往往用不了那么多,默认会全部打包,所以体积很大
- 可以指定moment中引入的locale不参与构建
- 但语言功能会失效,我们只需要在入口单独引入语言包即可
plugins: [
new webpack.IgnorePlugin({
contextRegExp: /moment$/,
resourceRegExp: /locale/,
})
]
指定单独抽离的模块
entry: {
main: "./src/index.js",
vender: ["react", "lodash"]
},
打包图片
{
test: /\.(jpg|png|gif|bms|svg)$/,
type: "asset/resource",
generator: {
filename: "images/[hash][ext]",
},
},
抽离css为单独文件
npm i mini-css-extract-plugin -D
- 分两部分,plugin里new一下,loader里去掉style-loader
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
...
module: {
rules: [
{
test: /\.css$/,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: "css/[name].css",
}),
],
...
代码分割
- 多入口会分割,但公共模块会重复打包,造成资源浪费
- 可将公共模块分开打包,其他地方引用即可,能有效的减少包的体积
optimization: {
splitChunks: {
chunks: "all",
minSize: 0,
minChunks: 2,
maxInitialRequests: 5,
maxAsyncRequests: 3,
cacheGroups: {
defaultVendors: {
test: /node_modules/,
minChunks: 1,
priority: 1,
},
default: {
minChunks: 1,
priority: 10,
reuseExistingChunk: true,
},
},
},
runtimeChunk: true,
}
Preload
- 异步模块会在加载的时候获取,可以使用插件加上魔法注释,来进行预加载
- 插件:
webpackpreload-webpack-plugin
- 使用:
btn.onclick = () => {
import(
"./two"
);
};
产出会额外生成txt文件
- 5里面会将依赖中的评论收集,并单独打个txt出来,实际上我并不期望它产出
const TerserPlugin = require("terser-webpack-plugin");
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
extractComments: false,
}),
],
}
};
依赖统计
- assets-webpack-plugin
- 会生成一个一个带有文件依赖的json
const AssetsPlugin = require("assets-webpack-plugin");
plugins:[
new AssetsPlugin({
filename: "xxx.json",
entrypoints: true,
integrity: true,
prettyPrint: true,
includeFilesWithoutChunk: true,
includeAuxiliaryAssets: true,
includeDynamicImportedAssets: true,
})
]
排除第三方库
- externals
- 指定某个模块不打包,比如react和react-dom
externals: {
react: "React",
"react-dom": "ReactDOM",
},
编译优化(提速)
- 切记dev环境不要开启代码压缩,会严重影响编译效率
experiments: {
lazyCompilation: true,
},
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
compact: false,
...
},
},
},
],
},
cache: true,
react热更新
- devserver本身自带的hot是webpack编译完成,页面刷新,但是会造成页面整体重新渲染,和数据重新加载
- npm i @pmmmwh/react-refresh-webpack-plugin react-refresh -D
const ReactRefreshPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
module: {
rules: [
{
test: /\.(js|jsx|ts|tsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader",
options: {
cacheDirectory: true,
compact: false,
presets: [
["@babel/preset-env"],
["@babel/preset-react", { runtime: "automatic" }],
"@babel/preset-typescript",
],
plugins: ["react-refresh/babel"],
},
},
},
],
},
plugins: [
new ReactRefreshPlugin(),
],
ssr提取css
- npm i isomorphic-style-loader-react18 -D