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即可),经过全面优化,兼顾开发体验和生产性能。

相关推荐
万少5 分钟前
万少用9个AI工具,帮朋友完成了一个"不可能"的项目
前端
小小小小宇7 分钟前
Vue `import` 为什么可以异步加载
前端
WMYeah12 分钟前
【无标题】
前端·rust·抽奖程序·跨平台抽奖程序
Unbelievabletobe13 分钟前
免费外汇api的响应时间在不同时段下的波动分析
大数据·开发语言·前端·python
大哥,带带弟弟22 分钟前
Grafana 前端嵌入与 JWT 鉴权实战
前端·grafana
小小小小宇23 分钟前
前端 V8 引擎垃圾回收机制与内存问题排查
前端
前端老石人34 分钟前
CSS 值定义语法
前端·css
sheeta199844 分钟前
Vue 前端基础笔记
前端·vue.js·笔记
小小小小宇44 分钟前
GitLab + GitLab Runner + Qiankun 微前端 + Nginx + Node 中间件 前端开发机从零搭建 CI/CD 全流程
前端
前端那点事1 小时前
别再写垃圾组件!Vue3 如何设计「真正可复用」的高质量通用组件
前端·vue.js