webpack优化——手把手教你优化webpack
概述
关于webpack常见的性能优化,我们可以从两个方面去着手考虑:
1.传输性能优化;通过优化代码体积等手段提高资源传输速度,达到优化目的;
2.构建过程优化;主要是提高webpack的打包速度;
一、传输性能优化
Tree Shaking
Webpack 已经默认开启了这个功能,无需其他配置
// package.json
"sideEffects": [
"**/*.css"
]
CDN加载库文件
//html
<% for (let i in htmlWebpackPlugin.options.cdns) { %>
<script src="<%= htmlWebpackPlugin.options.cdns[i] %>"></script>
<% } %>
//config
plugins:[
new HtmlWebpackPlugin({
title:'demo webpack5',
template:'./src/index.html',
cdns:['https://cdn.bootcss.com/jquery/3.4.1/jquery.js']
})
]
//externals
externals:{
jquery:'jQuery'
},
开放gzip压缩
const CompressionWebpackPlugin = require('compression-webpack-plugin');
new CompressionWebpackPlugin({
exclude: /.(html|map)$/i
}),
缓存开放
cache:{
type:'filesystem'
},
懒加载
//路由懒加载
component: () => import("@/views/pages/advertise/AdvertisePage.vue")
文件图片压缩
Babel
- 下载包:npm i @babel/plugin-transform-runtime -D
- 在babel-loader中添加:
{
loader: "babel-loader",
options: {
plugins: ["@babel/plugin-transform-runtime"], // 减少代码体积
},
},
提取重复代码,对模块都进行分割
optimization: {
// 代码分割配置
splitChunks: {
chunks: "all", // 对所有模块都进行分割
// 以下是默认值
// minSize: 20000, // 分割代码最小的大小
// minRemainingSize: 0, // 类似于minSize,最后确保提取的文件大小不能为0
// minChunks: 1, // 至少被引用的次数,满足条件才会代码分割
// maxAsyncRequests: 30, // 按需加载时并行加载的文件的最大数量
// maxInitialRequests: 30, // 入口js文件最大并行请求数量
// enforceSizeThreshold: 50000, // 超过50kb一定会单独打包(此时会忽略minRemainingSize、maxAsyncRequests、maxInitialRequests)
// cacheGroups: { // 组,哪些模块要打包到一个组
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
// },
// default: { // 其他没有写的配置会使用上面的默认值
// minChunks: 2, // 这里的minChunks权重更大
// priority: -20,
// reuseExistingChunk: true,
// },
// },
// 修改配置
cacheGroups: {
// 组,哪些模块要打包到一个组
// defaultVendors: { // 组名
// test: /[\\/]node_modules[\\/]/, // 需要打包到一起的模块
// priority: -10, // 权重(越大越高)
// reuseExistingChunk: true, // 如果当前 chunk 包含已从主 bundle 中拆分出的模块,则它将被重用,而不是生成新的模块
// },
default: {
// 其他没有写的配置会使用上面的默认值
minSize: 0, // 我们定义的文件体积太小了,所以要改打包的最小文件体积
minChunks: 2,
priority: -20,
reuseExistingChunk: true,
},
},
},
按需加载,动态导入。异步加载
console.log("hello main");
document.getElementById("btn").onclick = function () {
// 动态导入 --> 实现按需加载
// 即使只被引用了一次,也会代码分割
import("./math.js").then(({ sum }) => {
alert(sum(1, 2, 3, 4, 5));
});
};
二、构建过程优化
打包时间、体积分析
- 安装插件
npm i -D speed-measure-webpack-plugin
npm i -D webpack-bundle-analyzer
- 配置webpack.config.js
const SpeedMeasurePlugin = require("speed-measure-webpack-plugin");
const smp = new SpeedMeasurePlugin();
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
//smp.wrap时间分析要包裹配置文件
module.exports = smp.wrap({
// ...
plugins:[
//体积分析
new BundleAnalyzerPlugin({
analyzerMode:'disabled',
generateStatsFile:true,
})
]
});
- 运行命令
// package.json scripts下面加,启动体积分析服务
// "analyzer":"webpack-bundle-analyzer --port 8888 ./dist/stats.json"
开发模式
cheap-module-source-map:打包编译速度快,只包含行映射。source-map:包含行/列映射
module.exports = {
// 其他省略
mode: "development",
devtool: "cheap-module-source-map",
};
热模块替换
hot: true, // 开启HMR功能(只能用于开发环境,生产环境不需要了)
OneOf
用{oneOf: [ ]}把所有test包住,生产模式也是如此配置。
rules: [
{
oneOf: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/,
// use 数组里面 Loader 执行顺序是从右到左
use: ["style-loader", "css-loader"],
},
……
]
}
]
Include/Exclude 缩小搜索范围,提高性能
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
loader: "babel-loader",
},
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
}),
Cache开起缓存,提高二次构建速度
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
cacheCompression: false, // 缓存文件不要压缩
},
}
……
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
}),
Thread开启多进程同时处理 js 文件
- 下载包:npm i thread-loader -D
- 引入:const ThreadLoader = require("thread-loader");
- 配置:
// nodejs核心模块,直接使用
const os = require("os");
// cpu核数
const threads = os.cpus().length;
const TerserPlugin = require("terser-webpack-plugin");// 压缩js
……
{
test: /\.js$/,
// exclude: /node_modules/, // 排除node_modules代码不编译
include: path.resolve(__dirname, "../src"), // 也可以用包含
use: [
{
loader: "thread-loader", // 开启多进程
options: {
workers: threads, // 数量
},
},
{
loader: "babel-loader",
options: {
cacheDirectory: true, // 开启babel编译缓存
},
},
],
},
……
plugins: [
new ESLintWebpackPlugin({
// 指定检查文件的根目录
context: path.resolve(__dirname, "../src"),
exclude: "node_modules", // 默认值
cache: true, // 开启缓存
// 缓存目录
cacheLocation: path.resolve(
__dirname,
"../node_modules/.cache/.eslintcache"
),
threads, // 开启多进程
}),
// css压缩和放到optimization一样
// new CssMinimizerPlugin(),
],
optimization: {
minimize: true,
minimizer: [
// css压缩也可以写到optimization.minimizer里面,效果一样的
new CssMinimizerPlugin(),
// 当生产模式会默认开启TerserPlugin,但是我们需要进行其他配置,就要重新写了
new TerserPlugin({
parallel: threads // 开启多进程
})
],
},