webpack优化前端性能
Webpack 优化前端性能主要从构建时优化和运行时优化两个维度进行。以下是全面的优化方案:
1. 代码分割与按需加载
1.1 动态导入 (懒加载)
// React 路由懒加载
const Home = lazy(() => import(/* webpackChunkName: "home" */ './views/Home'))
const About = lazy(() => import(/* webpackChunkName: "about" */ './views/About'))
// Vue 组件懒加载
const AsyncComponent = () => ({
component: import('./AsyncComponent.vue'),
loading: LoadingComponent,
delay: 200
})
// 条件懒加载
document.getElementById('btn').addEventListener('click', () => {
import('./heavy-module.js')
.then(module => {
module.heavyFunction()
})
})
1.2 SplitChunks 代码分割
module.exports = {
optimization: {
splitChunks: {
chunks: 'all',
minSize: 20000, // 超过20KB才单独打包
maxSize: 244000, // 尝试拆分大于244KB的包
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
chunks: 'all'
},
react: {
test: /[\\/]node_modules[\\/](react|react-dom)[\\/]/,
name: 'react-vendor',
priority: 20
},
common: {
name: 'common',
minChunks: 2,
priority: 5,
reuseExistingChunk: true
},
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true
}
}
}
}
}
2. 资源压缩与优化
2.1 JavaScript 压缩
const TerserPlugin = require('terser-webpack-plugin')
module.exports = {
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true, // 多进程压缩
terserOptions: {
compress: {
drop_console: true, // 移除console
drop_debugger: true, // 移除debugger
pure_funcs: ['console.log'] // 移除特定函数
},
mangle: {
safari10: true // 解决Safari 10/11 bugs
}
},
extractComments: false // 不提取注释
})
]
}
}
2.2 CSS 压缩与提取
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
process.env.NODE_ENV === 'production'
? MiniCssExtractPlugin.loader
: 'style-loader',
'css-loader',
'postcss-loader' // 添加前缀等
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css'
})
],
optimization: {
minimizer: [
new CssMinimizerPlugin({
parallel: true
})
]
}
}
2.3 图片资源优化
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|jpeg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 8KB以下转base64
}
},
generator: {
filename: 'images/[name].[contenthash:8][ext]'
},
use: [
{
loader: 'image-webpack-loader',
options: {
mozjpeg: { progressive: true, quality: 65 },
optipng: { enabled: false },
pngquant: { quality: [0.65, 0.90], speed: 4 },
gifsicle: { interlaced: false },
webp: { quality: 75 }
}
}
]
}
]
}
}
3. 缓存策略
3.1 输出文件哈希命名
module.exports = {
output: {
filename: 'js/[name].[contenthash:8].js',
chunkFilename: 'js/[name].[contenthash:8].chunk.js'
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css'
})
]
}
3.2 模块ID优化
module.exports = {
optimization: {
moduleIds: 'deterministic', // 保持模块ID稳定
chunkIds: 'deterministic', // 保持块ID稳定
runtimeChunk: {
name: 'runtime' // 提取runtime代码
}
}
}
4. Tree Shaking 与副作用优化
4.1 启用 Tree Shaking
module.exports = {
mode: 'production',
optimization: {
usedExports: true, // 标记使用到的导出
sideEffects: false, // 开启副作用检测
concatenateModules: true // 模块作用域提升
}
}
4.2 package.json 配置
{
"name": "your-package",
"sideEffects": [
"*.css",
"*.scss",
"./src/polyfills.js"
]
}
4.3 Lodash 按需引入
// 安装 babel-plugin-lodash
npm install --save-dev babel-plugin-lodash
// .babelrc
{
"plugins": ["lodash"]
}
// 使用方式
import _ from 'lodash'
// 会被转换为:
// import _cloneDeep from 'lodash/cloneDeep'
// import _debounce from 'lodash/debounce'
5. 预加载与预获取
5.1 资源提示
// 预加载关键资源
import(/* webpackPreload: true */ './critical-module')
// 预获取非关键资源
import(/* webpackPrefetch: true */ './non-critical-module')
// 在路由组件中使用
const LazyComponent = lazy(() => import(
/* webpackPrefetch: true */
'./LazyComponent'
))
5.2 PreloadPlugin 自动预加载
const PreloadWebpackPlugin = require('preload-webpack-plugin')
module.exports = {
plugins: [
new PreloadWebpackPlugin({
rel: 'preload',
include: 'initial',
fileBlacklist: [/\.map$/, /hot-update/]
})
]
}
6. 打包分析优化
6.1 打包分析工具
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
module.exports = {
plugins: [
new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: 'bundle-report.html'
})
]
}
6.2 自定义分析插件
class BundleSizePlugin {
apply(compiler) {
compiler.hooks.done.tap('BundleSizePlugin', (stats) => {
const assets = stats.toJson().assets
assets.forEach(asset => {
const size = (asset.size / 1024).toFixed(2)
if (size > 500) { // 大于500KB警告
console.warn(`🚨 ${asset.name} 体积过大: ${size} KB`)
}
})
})
}
}
7. 运行时性能优化
7.1 长缓存优化
module.exports = {
optimization: {
splitChunks: {
cacheGroups: {
// 第三方库单独打包
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
},
// 提取webpack runtime
runtime: {
name: 'runtime',
chunks: 'all',
test: /runtime/
}
}
}
}
}
7.2 外部扩展 (Externals)
module.exports = {
externals: {
// 从CDN引入,不打包
react: 'React',
'react-dom': 'ReactDOM',
vue: 'Vue',
axios: 'axios'
}
}
// 在HTML中通过CDN引入
<script src="https://cdn.jsdelivr.net/npm/react@17/umd/react.production.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react-dom@17/umd/react-dom.production.min.js"></script>
8. 高级优化技巧
8.1 模块联邦 (微前端)
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin')
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'app',
filename: 'remoteEntry.js',
remotes: {
shared: 'shared@https://cdn.example.com/remoteEntry.js'
},
shared: {
react: { singleton: true },
'react-dom': { singleton: true }
}
})
]
}
8.2 PWA 优化
const WorkboxPlugin = require('workbox-webpack-plugin')
module.exports = {
plugins: [
new WorkboxPlugin.GenerateSW({
clientsClaim: true,
skipWaiting: true,
runtimeCaching: [{
urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
handler: 'CacheFirst',
options: {
cacheName: 'images',
expiration: {
maxEntries: 50,
maxAgeSeconds: 30 * 24 * 60 * 60 // 30天
}
}
}]
})
]
}
9. 开发环境性能优化
9.1 热更新优化
module.exports = {
devServer: {
hot: true,
port: 8080,
compress: true, // 开启gzip
overlay: true, // 错误覆盖层
stats: 'minimal', // 精简输出
clientLogLevel: 'warning' // 控制台日志级别
},
cache: {
type: 'memory', // 内存缓存
maxGenerations: 1
}
}
9.2 增量编译
module.exports = {
snapshot: {
managedPaths: [path.resolve(__dirname, 'node_modules')]
},
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename]
}
}
}
10. 性能监控与度量
10.1 性能预算
module.exports = {
performance: {
hints: 'warning',
maxEntrypointSize: 500000, // 入口点最大500KB
maxAssetSize: 300000, // 资源最大300KB
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js') || assetFilename.endsWith('.css')
}
}
}
10.2 构建监控
// webpack.config.js
class BuildMonitorPlugin {
apply(compiler) {
compiler.hooks.done.tap('BuildMonitorPlugin', (stats) => {
const info = stats.toJson()
console.log('构建时间:', info.time + 'ms')
console.log('资源数量:', info.assets.length)
// 发送构建报告
if (process.env.CI) {
this.sendReport(info)
}
})
}
}
优化效果评估指标
实施优化后,关注以下指标:
| 指标 | 优化目标 | 测量工具 |
|---|---|---|
| 首次加载时间 | < 3秒 | Lighthouse |
| 首次内容绘制 (FCP) | < 1.5秒 | Web Vitals |
| 最大内容绘制 (LCP) | < 2.5秒 | Web Vitals |
| 打包体积 | 主包 < 200KB | Bundle Analyzer |
| 缓存命中率 | > 90% | 浏览器Network |
通过综合运用这些优化策略,可以显著提升前端应用的加载性能和运行时性能。
挣钱养家

浙公网安备 33010602011771号