webpack优化手段
1. Webpack 性能优化手段
1.1. 减小文件体积
1.1.1. 使用 Tree Shaking
通过静态分析代码,移除未使用的代码。
// webpack.config.js
module.exports = {
// ...
optimization: {
usedExports: true,
},
};
1.1.2. 使用代码分割(Code Splitting)
将代码拆分为多个较小的块,按需加载。
// App.js
import(/* webpackChunkName: "my-chunk" */ './my-module').then((module) => {
// 使用导入的模块
});
// webpack.config.js
module.exports = {
// ...
optimization: {
splitChunks: {
chunks: 'all',
},
},
};
1.1.3. 使用动态导入(Dynamic Import)
按需加载模块。
// App.js
import('./my-module').then((module) => {
// 使用导入的模块
});
1.1.4. 压缩代码
使用 UglifyJS、Terser 等工具压缩 JavaScript 代码。
// webpack.config.js
const TerserPlugin = require('terser-webpack-plugin');
module.exports = {
// ...
optimization: {
minimize: true,
minimizer: [new TerserPlugin()],
},
};
1.1.5. 使用 Css 预处理器
如使用 Sass、Less 等,可以通过编译和压缩减小 CSS 文件体积。
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
],
},
};
1.1.6. 图片优化
使用压缩工具压缩图片,如使用 imagemin-webpack-plugin。
// webpack.config.js
const ImageminPlugin = require('imagemin-webpack-plugin').default;
module.exports = {
// ...
plugins: [
new ImageminPlugin({
test: /\.(jpe?g|png|gif|svg)$/i,
}),
],
};
1.2. 缓存优化
1.2.1. 使用持久化缓存
使用 webpack-manifest-plugin 生成一个映射清单,将模块 ID 映射到实际的输出文件,以便在构建过程中保持持久化的模块 ID。
// webpack.config.js
const ManifestPlugin = require('webpack-manifest-plugin');
module.exports = {
// ...
plugins: [
new ManifestPlugin(),
],
};
1.2.2. 文件名哈希化
通过添加哈希值到文件名中,确保文件内容发生变化时,生成的文件名也会发生变化,从而使浏览器能够正确地缓存新文件。
// webpack.config.js
module.exports = {
// ...
output: {
filename: '[name].[contenthash].js',
},
};
1.2.3. 使用缓存加载器(cache-loader、hard-source-webpack-plugin)
将中间结果缓存起来,避免重复的工作。
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: ['cache-loader', 'babel-loader'],
},
],
},
};
1.3. 并行构建
1.3.1. 使用 Happypack
将任务分解给多个子进程并行处理。
// webpack.config.js
const HappyPack = require('happypack');
module.exports = {
// ...
plugins: [
new HappyPack({
threads: 4, // 指定线程池的数量
loaders: ['babel-loader'], // 使用的 Loader
}),
],
module: {
rules: [
{
test: /\.js$/,
use: 'happypack/loader', // 使用 HappyPack 加载器
},
],
},
};
1.3.2. 使用 Thread-loader
将耗时的 Loader 任务分配给 Worker 线程处理。
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: ['thread-loader', 'babel-loader'], // 使用 thread-loader 和 babel-loader
},
],
},
};
1.4. 减少构建时间
1.4.1. 使用 resolve.modules 配置
缩小模块搜索范围,减少模块查找时间。
// webpack.config.js
module.exports = {
// ...
resolve: {
modules: ['src', 'node_modules'], // 指定模块的搜索路径
},
};
1.4.2. 使用 resolve.extensions 配置
减少模块文件后缀的解析尝试。
// webpack.config.js
module.exports = {
// ...
resolve: {
extensions: ['.js', '.jsx', '.json'], // 指定模块文件后缀的解析尝试顺序
},
};
1.4.3. 使用 Externals
将一些不需要打包的模块排除在构建之外。
// webpack.config.js
module.exports = {
// ...
externals: {
lodash: '_', // 指定外部引入的模块
},
};
1.5. 优化输出结果
1.5.1. 使用 DLL(动态链接库)
将基础模块提前编译成静态文件,加快构建速度。
webpack.dll.config.js:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: {
vendor: ['react', 'react-dom'], // 指定基础模块
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].dll.js',
library: '[name]_dll', // 输出的全局变量名
},
plugins: [
new webpack.DllPlugin({
name: '[name]_dll',
path: path.resolve(__dirname, 'dist', '[name].manifest.json'),
}),
],
};
webpack.config.js:
const path = require('path');
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.DllReferencePlugin({
manifest: require('./dist/vendor.manifest.json'),
}),
],
};
1.5.2. 使用 Scope Hoisting(作用域提升)
将模块封装成函数作用域,减少模块包裹代码的体积。
// webpack.config.js
module.exports = {
// ...
optimization: {
concatenateModules: true,
},
};
1.6. 使用优化插件
1.6.1. 使用 webpack.optimize.ModuleConcatenationPlugin
启用模块串联,减少模块封装代码的体积。
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.optimize.ModuleConcatenationPlugin(),
],
};
1.6.2. 使用 webpack.IgnorePlugin
忽略某些特定的模块,在打包过程中不引入它们。
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale/, // 忽略 moment.js 的 locale 目录
contextRegExp: /moment/, // 忽略 moment.js 的 context
}),
],
};
1.6.3. 使用 Webpack-bundle-analyzer
可视化地分析构建结果,找出体积较大的模块。
// webpack.config.js
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
// ...
plugins: [
new BundleAnalyzerPlugin(),
],
};
1.7. 使用 Webpack-merge
合并 webpack 配置的工具,可以用于区分开发环境和生产环境的配置。减少重复代码
npm install webpack-merge --save-dev
然后,我们将创建三个配置文件:webpack.common.js、webpack.dev.js 和 webpack.prod.js。
在 webpack.common.js 中定义通用的配置项,包括入口、输出路径、加载器、插件等:
// webpack.common.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
// 加载器规则
// ...
],
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
}),
// 其他插件
// ...
],
};
我们创建 webpack.dev.js 文件,该文件包含开发环境的特定配置,如开发服务器配置、源映射等:
// webpack.dev.js
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
module.exports = merge(commonConfig, {
mode: 'development',
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
port: 3000,
},
module: {
rules: [
// 开发环境的加载器规则
// ...
],
},
plugins: [
// 开发环境的插件
// ...
],
});
我们创建 webpack.prod.js 文件,该文件包含生产环境的特定配置,如压缩代码、提取 CSS、代码分割等:
// webpack.prod.js
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.common.js');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = merge(commonConfig, {
mode: 'production',
devtool: 'source-map',
module: {
rules: [
// 生产环境的加载器规则
// ...
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
// 其他插件
// ...
],
optimization: {
minimizer: [new TerserPlugin()],
splitChunks: {
chunks: 'all',
},
},
});
最后,在 package.json 中配置脚本,以便在开发环境和生产环境中使用相应的配置文件:
{
"scripts": {
"dev": "webpack-dev-server --config webpack.dev.js",
"build": "webpack --config webpack.prod.js"
}
}