下面是一个针对现代Web开发的通用Webpack 5配置方案,经过优化,支持多种框架和技术栈,包含最佳实践和性能优化策略。
jsx
// webpack.config.js - 通用高性能配置
const path = require('path');
const { DefinePlugin, ProgressPlugin } = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const CompressionPlugin = require('compression-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production';
const isDev = !isProduction;
const isAnalyze = env && env.analyze;
return {
// 入口配置(支持多入口和动态导入)
entry: {
main: './src/index.js',
vendor: ['react', 'react-dom'] // 常用库分离
},
// 输出配置(缓存策略优化)
output: {
filename: isProduction
? 'js/[name].[contenthash:8].bundle.js'
: 'js/[name].bundle.js',
chunkFilename: isProduction
? 'js/[name].[contenthash:8].chunk.js'
: 'js/[name].chunk.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
assetModuleFilename: 'assets/[hash][ext][query]',
},
// 开发环境配置
devtool: isProduction
? 'source-map'
: 'cheap-module-source-map',
mode: isProduction ? 'production' : 'development',
// 模块规则配置
module: {
rules: [
// JS/JSX处理(包含缓存和多线程支持)
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true,
presets: [
['@babel/preset-env', {
modules: false,
useBuiltIns: 'usage',
corejs: 3
}],
'@babel/preset-react'
],
plugins: [
'@babel/plugin-transform-runtime',
'@babel/plugin-proposal-class-properties',
['babel-plugin-import', {
"libraryName": "antd",
"libraryDirectory": "es",
"style": true
}]
]
}
},
{
loader: 'thread-loader',
options: {
workers: require('os').cpus().length - 1,
poolTimeout: isDev ? Infinity : 2000
}
}
]
},
// TypeScript支持(可选)
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
// CSS模块(本地作用域)
{
test: /\.module\.(sa|sc|c)ss$/,
use: [
isProduction
? MiniCssExtractPlugin.loader
: 'style-loader',
{
loader: 'css-loader',
options: {
modules: {
localIdentName: isProduction
? '[hash:base64:8]'
: '[path][name]__[local]',
exportLocalsConvention: 'camelCaseOnly'
},
sourceMap: isDev
}
},
'postcss-loader',
{
loader: 'sass-loader',
options: {
sourceMap: isDev
}
}
]
},
// 全局CSS(无模块)
{
test: /\.(sa|sc|c)ss$/,
exclude: /\.module\.css$/,
use: [
isProduction
? MiniCssExtractPlugin.loader
: 'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: isDev
}
},
'postcss-loader',
{
loader: 'sass-loader',
options: {
sourceMap: isDev
}
}
]
},
// 图片资源(自动优化)
{
test: /\.(png|jpe?g|gif|webp|avif)(\?.*)?$/i,
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: 8 * 1024 // 小于8KB转为Base64
}
},
generator: {
filename: 'images/[contenthash][ext][query]'
}
},
// SVG处理(可选择转为组件)
{
test: /\.svg(\?v=\w+)?$/,
oneOf: [
{
resourceQuery: /component/,
use: [
'@svgr/webpack',
'url-loader'
]
},
{
type: 'asset/resource',
generator: {
filename: 'svg/[contenthash][ext][query]'
}
}
]
},
// 字体资源
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
type: 'asset/resource',
generator: {
filename: 'fonts/[contenthash][ext][query]'
}
},
// 媒体资源(视频/音频)
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
type: 'asset/resource',
generator: {
filename: 'media/[contenthash][ext][query]'
}
},
// WebAssembly支持
{
test: /\.wasm$/,
type: 'webassembly/async'
},
// MDX支持(文档驱动)
{
test: /\.mdx?$/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-react']
}
},
'@mdx-js/loader'
]
}
]
},
// 插件系统
plugins: [
// 构建进度显示
new ProgressPlugin({
entries: true,
modules: true,
modulesCount: 100,
profile: true
}),
// 清理构建目录
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'**/*',
'!manifest.json',
'!robots.txt',
'!favicon.ico'
],
protectWebpackAssets: false
}),
// HTML模板
new HtmlWebpackPlugin({
title: '现代Web应用',
template: './public/index.html',
filename: 'index.html',
favicon: './public/favicon.ico',
inject: 'body',
minify: isProduction ? {
collapseWhitespace: true,
removeComments: true,
removeRedundantAttributes: true
} : false,
scriptLoading: 'module',
meta: {
viewport: 'width=device-width, initial-scale=1, shrink-to-fit=no',
'theme-color': '#4285f4'
},
chunks: ['main', 'vendor']
}),
// CSS提取
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash:8].css',
chunkFilename: 'css/[name].[contenthash:8].chunk.css',
ignoreOrder: true
}),
// 全局常量
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(
isProduction ? 'production' : 'development'
),
'process.env.APP_VERSION': JSON.stringify(
process.env.npm_package_version || '1.0.0'
),
'__IS_DEVELOPMENT__': isDev
}),
// 复制静态资源
new CopyPlugin({
patterns: [
{
from: 'public',
to: '.',
globOptions: {
ignore: ['**/index.html']
}
}
]
}),
// Gzip压缩
isProduction && new CompressionPlugin({
test: /\.(js|css|html|svg|json)$/,
filename: '[path][base].gz',
algorithm: 'gzip',
threshold: 1024 * 10, // 10KB以上压缩
minRatio: 0.8,
exclude: /\.(br|gz)$/
}),
// Brotli压缩(更优算法)
isProduction && new CompressionPlugin({
test: /\.(js|css|html|svg|json)$/,
filename: '[path][base].br',
algorithm: 'brotliCompress',
compressionOptions: { level: 11 },
threshold: 1024 * 10,
minRatio: 0.8,
exclude: /\.(br|gz)$/
}),
// 包分析工具
isAnalyze && new BundleAnalyzerPlugin({
analyzerMode: 'static',
openAnalyzer: false,
reportFilename: '../report/bundle-report.html'
})
].filter(Boolean),
// 优化配置
optimization: {
minimize: isProduction,
minimizer: [
// JS压缩
new TerserPlugin({
parallel: true,
extractComments: false,
terserOptions: {
compress: {
drop_console: isProduction,
drop_debugger: isProduction,
comparisons: false
},
mangle: true,
output: {
ecma: 5,
comments: false,
ascii_only: true
}
}
}),
// CSS压缩
new CssMinimizerPlugin({
minimizerOptions: {
preset: [
"default",
{
discardComments: { removeAll: true },
cssDeclarationSorter: true
}
]
},
parallel: 4
})
],
// 代码分割
splitChunks: {
chunks: 'all',
minSize: 30000,
minChunks: 1,
maxAsyncRequests: 20,
maxInitialRequests: 20,
automaticNameDelimiter: '~',
cacheGroups: {
// 分离第三方库
vendors: {
test: /[\\/]node_modules[\\/]/,
name(module) {
const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
return `npm.${packageName.replace('@', '')}`;
},
priority: -10
},
// 分离公共模块
common: {
name: 'common',
minChunks: 2,
priority: -20,
reuseExistingChunk: true
},
// CSS文件优化
styles: {
name: "styles",
type: "css/mini-extract",
chunks: "all",
enforce: true
}
}
},
// 运行时单独分离
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`
},
// 模块ID算法优化
moduleIds: isProduction ? 'deterministic' : 'named',
chunkIds: isProduction ? 'deterministic' : 'named'
},
// 开发服务器
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 9000,
hot: true,
open: '/',
historyApiFallback: true,
client: {
overlay: {
errors: true,
warnings: false
},
progress: true,
reconnect: 5
},
proxy: {
'/api': {
target: 'http://localhost:3000',
changeOrigin: true,
pathRewrite: { '^/api': '' }
}
},
devMiddleware: {
writeToDisk: true // 用于调试生成的文件
}
},
// 解析配置(重要!)
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx', '.json', '.scss', '.css'],
alias: {
'@': path.resolve('src'),
'@assets': path.resolve('src/assets'),
'@components': path.resolve('src/components'),
'@pages': path.resolve('src/pages'),
'@utils': path.resolve('src/utils'),
'@store': path.resolve('src/store'),
'@styles': path.resolve('src/styles'),
// 添加框架别名支持
'react-native$': 'react-native-web'
},
fallback: {
"crypto": require.resolve("crypto-browserify"),
"stream": require.resolve("stream-browserify"),
"buffer": require.resolve("buffer/"),
"assert": require.resolve("assert/"),
"https": require.resolve("https-browserify"),
"http": require.resolve("stream-http"),
"url": require.resolve("url/"),
"zlib": require.resolve("browserify-zlib"),
"path": require.resolve("path-browserify"),
"fs": false
}
},
// 外部依赖(优化构建大小)
externals: isProduction
? {
'react': 'React',
'react-dom': 'ReactDOM',
'lodash': '_',
'moment': 'moment'
}
: {},
// 性能设置
performance: {
maxAssetSize: process.env.NODE_ENV === 'production' ? 512 * 1024 : Infinity,
maxEntrypointSize: process.env.NODE_ENV === 'production' ? 512 * 1024 : Infinity,
hints: process.env.NODE_ENV === 'production' ? 'warning' : false
},
// 实验性特性
experiments: {
syncWebAssembly: true,
asyncWebAssembly: true,
topLevelAwait: true
}
};
};
关键优化策略说明
🚀 性能优化
-
代码分割优化
jssplitChunks: { cacheGroups: { vendors: { test: /[\\/]node_modules[\\/]/, name: module => `npm.${module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1].replace('@', '')}` } } }
-
缓存策略
jsoutput: { filename: 'js/[name].[contenthash:8].bundle.js', chunkFilename: 'js/[name].[contenthash:8].chunk.js' }
-
多线程处理
jsuse: [ { loader: 'thread-loader', options: { workers: require('os').cpus().length - 1 } }, 'babel-loader' ]
📦 模块处理优化
-
智能资源处理
- 图片:<8KB自动转为Base64
- SVG:可选择作为组件导入或作为资源
js{ test: /\.svg(\?v=\w+)?$/, oneOf: [ { resourceQuery: /component/, use: ['@svgr/webpack'] }, { type: 'asset/resource' } ] }
-
多格式支持
- WebAssembly (WASM)
- MDX (Markdown + JSX)
- TypeScript
🌈 开发体验优化
-
渐进式加载提示
jsnew HtmlWebpackPlugin({ scriptLoading: 'module', preload: '**/*.css', prefetch: ['app.chunk.js'] })
-
开发服务器优化
jsdevServer: { client: { overlay: { errors: true, warnings: false }, progress: true, reconnect: 5 } }
-
HOT热更新与模块联邦支持
💡 高级特性支持
-
WebAssembly集成
jsexperiments: { syncWebAssembly: true, asyncWebAssembly: true, topLevelAwait: true }
-
模块联邦支持
js// 可添加ModuleFederationPlugin new ModuleFederationPlugin({ name: 'myApp', filename: 'remoteEntry.js', exposes: { './Button': './src/components/Button.js' }, remotes: { otherApp: 'otherApp@https://other-domain.com/remoteEntry.js' } })
执行脚本 (package.json)
json
{
"scripts": {
"dev": "webpack serve --mode development",
"build": "webpack --mode production",
"build:analyze": "webpack --mode production --env analyze",
"start": "webpack serve --open",
"lint": "eslint . --ext .js,.jsx"
},
"devDependencies": {
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.15.1",
"html-webpack-plugin": "^5.5.3",
"clean-webpack-plugin": "^4.0.0",
"thread-loader": "^4.0.2",
"babel-loader": "^9.1.3",
"@babel/core": "^7.22.11",
"@babel/preset-env": "^7.22.10",
"@babel/preset-react": "^7.22.5",
"css-loader": "^6.8.1",
"sass-loader": "^13.3.2",
"postcss-loader": "^8.0.0",
"mini-css-extract-plugin": "^2.7.6",
"terser-webpack-plugin": "^5.3.9",
"css-minimizer-webpack-plugin": "^6.2.0",
"copy-webpack-plugin": "^11.0.0",
"compression-webpack-plugin": "^10.0.0",
"webpack-bundle-analyzer": "^4.9.1",
"sass": "^1.67.0"
},
"dependencies": {
"antd": "^5.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@babel/runtime": "^7.22.11"
}
}
最佳实践指南
1. 项目结构推荐
├── public # 静态资源
├── src # 源代码
│ ├── assets # 静态资源
│ ├── components # 通用组件
│ ├── pages # 页面组件
│ ├── layouts # 布局组件
│ ├── store # 状态管理
│ ├── services # API服务
│ ├── utils # 工具函数
│ ├── styles # 全局样式
│ ├── hooks # 自定义Hooks
│ ├── config # 配置文件
│ ├── types # TS类型定义
│ ├── app.js # 主应用组件
│ └── index.js # 入口文件
2. 多环境配置
创建webpack.config.js
和webpack.prod.config.js
文件:
js
// webpack.prod.config.js
const { merge } = require('webpack-merge');
const commonConfig = require('./webpack.config.js');
module.exports = (env) => merge(commonConfig(env), {
mode: 'production',
optimization: {
minimize: true,
// 生产环境特有优化
},
plugins: [
// 生产环境特有插件
]
});
3. 路由懒加载(React示例)
jsx
import React, { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import(/* webpackChunkName: "dashboard" */ './pages/Dashboard'));
const Settings = lazy(() => import(/* webpackChunkName: "settings" */ './pages/Settings'));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<Routes>
<Route path="/" element={<Dashboard />} />
<Route path="/settings" element={<Settings />} />
</Routes>
</Suspense>
);
}
4. 高级缓存控制
通过服务端实现长缓存策略:
nginx
# Nginx配置
location ~* \.(js|css)$ {
expires 365d;
add_header Cache-Control "public, immutable";
}
location ~* \.(woff|woff2|jpg|png|svg)$ {
expires 30d;
add_header Cache-Control "public";
}
注意事项
- Tree Shaking 确保在package.json中添加
"sideEffects": false
属性 - 使用ES6模块语法让Webpack更好的优化
- 避免在库中使用
module.exports = ...
导出 - 在大型项目中使用TS和类型检查
- 定期运行
npm run build:analyze
检查包大小
本配置适用于Web应用开发,支持Vue等主流框架(适当调整loader即可),经过全面优化,兼顾开发体验和生产性能。