Webpack 5 高性能配置方案

下面是一个针对现代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
    }
  };
};

关键优化策略说明

🚀 性能优化

  1. 代码分割优化

    js 复制代码
    splitChunks: {
      cacheGroups: {
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: module => `npm.${module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1].replace('@', '')}`
        }
      }
    }
  2. 缓存策略

    js 复制代码
    output: {
      filename: 'js/[name].[contenthash:8].bundle.js',
      chunkFilename: 'js/[name].[contenthash:8].chunk.js'
    }
  3. 多线程处理

    js 复制代码
    use: [
      { loader: 'thread-loader', options: { workers: require('os').cpus().length - 1 } },
      'babel-loader'
    ]

📦 模块处理优化

  1. 智能资源处理

    • 图片:<8KB自动转为Base64
    • SVG:可选择作为组件导入或作为资源
    js 复制代码
    {
      test: /\.svg(\?v=\w+)?$/,
      oneOf: [
        { resourceQuery: /component/, use: ['@svgr/webpack'] },
        { type: 'asset/resource' }
      ]
    }
  2. 多格式支持

    • WebAssembly (WASM)
    • MDX (Markdown + JSX)
    • TypeScript

🌈 开发体验优化

  1. 渐进式加载提示

    js 复制代码
    new HtmlWebpackPlugin({
      scriptLoading: 'module',
      preload: '**/*.css',
      prefetch: ['app.chunk.js']
    })
  2. 开发服务器优化

    js 复制代码
    devServer: {
      client: {
        overlay: { errors: true, warnings: false },
        progress: true,
        reconnect: 5
      }
    }
  3. HOT热更新与模块联邦支持

💡 高级特性支持

  1. WebAssembly集成

    js 复制代码
    experiments: {
      syncWebAssembly: true,
      asyncWebAssembly: true,
      topLevelAwait: true
    }
  2. 模块联邦支持

    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.jswebpack.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";
}

注意事项

  1. Tree Shaking 确保在package.json中添加"sideEffects": false属性
  2. 使用ES6模块语法让Webpack更好的优化
  3. 避免在库中使用module.exports = ...导出
  4. 在大型项目中使用TS和类型检查
  5. 定期运行npm run build:analyze检查包大小

本配置适用于Web应用开发,支持Vue等主流框架(适当调整loader即可),经过全面优化,兼顾开发体验和生产性能。

相关推荐
Hurry64 分钟前
web应用服务器tomcat
java·前端·tomcat
烛阴1 小时前
Sin -- 重复的、流动的波浪
前端·webgl
太阳伞下的阿呆2 小时前
mac安装node.js
macos·node.js
北'辰3 小时前
DeepSeek智能考试系统智能体
前端·后端·架构·开源·github·deepseek
前端历劫之路3 小时前
🔥 1.30 分!我的 JS 库 Mettle.js 杀入全球性能榜,紧追 Vue
前端·javascript·vue.js
Murray的菜鸟笔记4 小时前
【Vue Router】路由模式、懒加载、守卫、权限、缓存
前端·vue router
苏格拉没有底了5 小时前
由频繁创建3D火焰造成的内存泄漏问题
前端
阿彬爱学习5 小时前
大模型在垂直场景的创新应用:搜索、推荐、营销与客服新玩法
前端·javascript·easyui
橙序员小站5 小时前
通过trae开发你的第一个Chrome扩展插件
前端·javascript·后端