文章目录
- 
- 一、性能优化进阶
- 
- [1.1 构建速度优化](#1.1 构建速度优化)
- 
- [1.1.1 并行编译与资源缓存](#1.1.1 并行编译与资源缓存)
- [1.1.2 非必要任务延迟处理](#1.1.2 非必要任务延迟处理)
 
- [1.2 打包体积优化](#1.2 打包体积优化)
- 
- [1.2.1 精细化资源压缩](#1.2.1 精细化资源压缩)
- [1.2.2 第三方依赖优化](#1.2.2 第三方依赖优化)
 
 
- 二、代码分割高级策略
- 
- [2.1 splitChunks 自定义配置](#2.1 splitChunks 自定义配置)
- [2.2 动态导入与预加载](#2.2 动态导入与预加载)
 
- [三、Module Federation 跨应用共享](#三、Module Federation 跨应用共享)
- 
- [3.1 核心概念与价值](#3.1 核心概念与价值)
- [3.2 实战配置(Webpack 5+)](#3.2 实战配置(Webpack 5+))
- 
- [3.2.1 远程应用(暴露共享模块)](#3.2.1 远程应用(暴露共享模块))
- [3.2.2 宿主应用(引入远程模块)](#3.2.2 宿主应用(引入远程模块))
- [3.2.3 宿主应用使用远程模块](#3.2.3 宿主应用使用远程模块)
 
 
- [四、Tree Shaking 深度实践](#四、Tree Shaking 深度实践)
- 
- [4.1 基础配置与生效条件](#4.1 基础配置与生效条件)
- [4.2 常见失效问题与解决](#4.2 常见失效问题与解决)
 
- 五、缓存策略优化
- 
- [5.1 长期缓存配置](#5.1 长期缓存配置)
- [5.2 缓存失效控制](#5.2 缓存失效控制)
 
- [六、自定义 Loader 与 Plugin](#六、自定义 Loader 与 Plugin)
- 
- [6.1 自定义 Loader 开发(代码替换示例)](#6.1 自定义 Loader 开发(代码替换示例))
- [6.2 自定义 Plugin 开发(版权注释示例)](#6.2 自定义 Plugin 开发(版权注释示例))
 
- 七、多环境配置方案
- 
- [7.1 配置文件拆分](#7.1 配置文件拆分)
- [7.2 环境融合与变量注入](#7.2 环境融合与变量注入)
- [7.3 启动脚本配置](#7.3 启动脚本配置)
 
- 八、避坑与最佳实践
- 
- [8.1 常见进阶问题解决](#8.1 常见进阶问题解决)
 
 
一、性能优化进阶
1.1 构建速度优化
1.1.1 并行编译与资源缓存
            
            
              javascript
              
              
            
          
          // webpack.config.js
const path = require('path');
const TerserPlugin = require('terser-webpack-plugin');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
module.exports = {
     // 1. 多进程压缩
     optimization: {
       minimizer: [
         new TerserPlugin({
           parallel: true, // 启用多进程压缩
           threads: 4 // 指定4个线程
         })
       ]
     },
     // 2. 持久化缓存(Webpack 5+)
     cache: {
       type: 'filesystem', // 磁盘缓存(默认内存缓存)
       cacheDirectory: path.resolve(__dirname, '.webpack_cache'),
       buildDependencies: {
         config: [__filename] // 配置文件变更时重建缓存
       }
     },
     // 3. 模块缓存加速
     plugins: [new HardSourceWebpackPlugin()], // 缓存模块构建结果
     module: {
       rules: [
         {
           test: /.js$/,
           exclude: /node_modules/,
           use: [
             'cache-loader', // 缓存loader结果
             {
               loader: 'babel-loader',
               options: {
                 cacheDirectory: true // babel-loader内置缓存
               }
             }
           ]
         }
       ]
     }
};1.1.2 非必要任务延迟处理
            
            
              javascript
              
              
            
          
          // 仅生产环境启用耗时插件
module.exports = (env) => ({
     plugins: [
       env.production && new BundleAnalyzerPlugin({
         analyzerMode: 'static', // 生成静态报告文件(不启动服务)
         openAnalyzer: false // 不自动打开报告
       })
     ].filter(Boolean) // 过滤false值
});1.2 打包体积优化
1.2.1 精细化资源压缩
            
            
              javascript
              
              
            
          
          # 安装压缩工具
npm install cssnano postcss-loader imagemin-webpack-plugin --save-dev
            
            
              javascript
              
              
            
          
          // webpack.config.js
const CssNanoPlugin = require('cssnano-webpack-plugin');
const ImageminPlugin = require('imagemin-webpack-plugin').default;
module.exports = {
     module: {
       rules: [
         {
           test: /.css$/,
           use: ['style-loader', 'css-loader', 'postcss-loader']
         }
       ]
     },
     plugins: [
       // CSS压缩
       new CssNanoPlugin({
         preset: ['default', { discardComments: { removeAll: true } }]
       }),
       // 图片压缩
       new ImageminPlugin({
         test: /.(png|jpe?g|gif)$/i,
         optipng: { optimizationLevel: 5 }, // PNG压缩级别
         jpegtran: { progressive: true } // JPG渐进式压缩
       })
     ]
};1.2.2 第三方依赖优化
            
            
              JAVASCRIPT
              
              
            
          
          // 1. 排除无需打包的依赖(通过CDN引入)
module.exports = {
     externals: {
       lodash: '_',
       react: 'React',
       'react-dom': 'ReactDOM'
     }
};
// 2. HTML中引入CDN资源
<!-- public/index.html -->
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/react@18.2.0/umd/react.production.min.js"></script>二、代码分割高级策略
2.1 splitChunks 自定义配置
            
            
              javascript
              
              
            
          
          // webpack.config.js
module.exports = {
     optimization: {
       splitChunks: {
         chunks: 'all', // 分割所有类型chunk(初始+异步)
         minSize: 20000, // 最小分割体积20KB
         minRemainingSize: 0, // 确保分割后剩余体积不为0
         minChunks: 1, // 至少被引用1次才分割
         maxAsyncRequests: 30, // 异步加载最大请求数
         maxInitialRequests: 30, // 初始加载最大请求数
         enforceSizeThreshold: 50000, // 强制分割阈值50KB
         cacheGroups: {
           // 1. 分割第三方依赖
           vendors: {
             test: /[/]node_modules[/]/,
             priority: -10, // 优先级(数值越大越优先)
             reuseExistingChunk: true, // 复用已存在的chunk
             name: 'vendors' // 输出文件名
           },
           // 2. 分割公共业务代码
           common: {
             name: 'common',
             minChunks: 2, // 至少被2个模块引用
             priority: -20,
             reuseExistingChunk: true
           },
           // 3. 分割CSS资源(需配合mini-css-extract-plugin)
           styles: {
             name: 'styles',
             test: /.css$/,
             chunks: 'all',
             enforce: true // 强制分割
           }
         }
       }
     }
};2.2 动态导入与预加载
            
            
              javascript
              
              
            
          
          // 1. 基础动态导入(路由懒加载场景)
const Home = () => import('./Home');
const About = () => import('./About');
// 2. 带预加载的动态导入
const Profile = () => import(/* webpackPrefetch: true */ './Profile');
// 生成<link rel="prefetch" href="profile.js"> 浏览器空闲时加载
// 3. 预加载当前页面所需资源
const Chart = () => import(/* webpackPreload: true */ './Chart');
// 生成<link rel="preload" href="chart.js"> 随当前页面优先加载三、Module Federation 跨应用共享
3.1 核心概念与价值
Module Federation 实现了跨应用的代码共享,无需 npm 包安装与构建,直接通过 CDN 在运行时共享模块,解决了微前端架构中公共依赖冗余、组件复用困难的问题。
3.2 实战配置(Webpack 5+)
3.2.1 远程应用(暴露共享模块)
            
            
              javascript
              
              
            
          
          # 安装依赖
npm install webpack@5 webpack-cli html-webpack-plugin --save-dev
            
            
              javascript
              
              
            
          
          // remote-webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
     entry: './src/index.js',
     output: {
       publicPath: 'http://localhost:3001/' // 远程应用CDN地址
     },
     plugins: [
       new ModuleFederationPlugin({
         name: 'remoteApp', // 远程应用名称
         filename: 'remoteEntry.js', // 暴露入口文件
         exposes: {
           './Button': './src/Button', // 暴露Button组件
           './utils': './src/utils' // 暴露工具函数
         },
         shared: {
           react: { singleton: true }, // 单例模式共享react
           'react-dom': { singleton: true }
         }
       }),
       new HtmlWebpackPlugin({ template: './public/index.html' })
     ],
     devServer: { port: 3001 }
};3.2.2 宿主应用(引入远程模块)
            
            
              javascript
              
              
            
          
          // host-webpack.config.js
const { ModuleFederationPlugin } = require('webpack').container;
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
     entry: './src/index.js',
     plugins: [
       new ModuleFederationPlugin({
         name: 'hostApp',
         remotes: {
           remoteApp: 'remoteApp@http://localhost:3001/remoteEntry.js'
         },
         shared: {
           react: { singleton: true },
           'react-dom': { singleton: true }
         }
       }),
       new HtmlWebpackPlugin({ template: './public/index.html' })
     ],
     devServer: { port: 3000 }
};3.2.3 宿主应用使用远程模块
            
            
              javascript
              
              
            
          
          // src/App.js
import React from 'react';
// 引入远程组件
const RemoteButton = React.lazy(() => import('remoteApp/Button'));
// 引入远程工具函数
import { formatDate } from 'remoteApp/utils';
function App() {
     return (
       <div>
         <h1>宿主应用</h1>
         <React.Suspense fallback="加载中...">
           <RemoteButton label="共享按钮" />
         </React.Suspense>
         <p>{formatDate(new Date())}</p>
       </div>
     );
}
export default App;四、Tree Shaking 深度实践
4.1 基础配置与生效条件
            
            
              javascript
              
              
            
          
          // 1. package.json 标记无副作用文件
{
     "sideEffects": [
       "*.css", // CSS文件有副作用,不被Tree Shaking删除
       "*.less"
     ]
}
// 2. webpack.config.js 启用优化
module.exports = {
     mode: 'production', // 生产模式自动启用Tree Shaking
     optimization: {
       usedExports: true, // 标记未使用的导出
       minimize: true // 配合Terser删除死代码
     }
};4.2 常见失效问题与解决
- 
CommonJS 模块无法 Tree Shaking 解决方案:使用 ES Module 语法(import/export),避免 require 
            
            
              javascript
              
              
            
          
          // 错误:CommonJS语法无法Tree Shaking
const { unusedFunc } = require('./utils');
// 正确:ES Module支持Tree Shaking
import { usedFunc } from './utils';- 
副作用代码误删 解决方案:在 sideEffects 中声明有副作用的文件 
            
            
              javascript
              
              
            
          
          "sideEffects": [
     "./src/polyfill.js", // 全局polyfill有副作用
     "*.css"
]- 
动态导入导致分析失败 解决方案:明确导出意图,避免模糊导入 
            
            
              javascript
              
              
            
          
          // 错误:模糊导入难以分析
import * as utils from './utils';
// 正确:精确导入需要的模块
import { formatDate } from './utils';五、缓存策略优化
5.1 长期缓存配置
            
            
              javascript
              
              
            
          
          // webpack.config.js
module.exports = {
     output: {
       filename: '[name].[contenthash:8].js', // 基于内容哈希命名
       chunkFilename: '[name].[contenthash:8].chunk.js',
       assetModuleFilename: 'assets/[name].[contenthash:8].[ext]'
     },
     optimization: {
       moduleIds: 'deterministic', // 稳定的模块ID(3-4位数字)
       chunkIds: 'deterministic', // 稳定的chunkID
       runtimeChunk: 'single' // 提取runtime到单独文件
     }
};5.2 缓存失效控制
            
            
              javascript
              
              
            
          
          // 1. 排除第三方依赖的哈希变化影响
module.exports = {
     optimization: {
       splitChunks: {
         cacheGroups: {
           vendors: {
             name: 'vendors',
             test: /node_modules/,
             chunks: 'all'
           }
         }
       }
     }
};
// 2. 手动更新版本触发缓存失效
const packageJson = require('./package.json');
module.exports = {
     plugins: [
       new webpack.DefinePlugin({
         'APP_VERSION': JSON.stringify(packageJson.version)
       })
     ]
};六、自定义 Loader 与 Plugin
6.1 自定义 Loader 开发(代码替换示例)
            
            
              javascript
              
              
            
          
          // loaders/replace-loader.js
module.exports = function(source) {
     // 替换代码中的特定字符串
     const result = source.replace(/{{VERSION}}/g, '1.0.0');
     return result;
};
// 配置使用
module.exports = {
     module: {
       rules: [
         {
           test: /.js$/,
           use: './loaders/replace-loader'
         }
       ]
     }
};6.2 自定义 Plugin 开发(版权注释示例)
            
            
              javascript
              
              
            
          
          // plugins/copyright-plugin.js
class CopyrightPlugin {
     constructor(options = {}) {
       this.author = options.author || 'Unknown';
     }
     apply(compiler) {
       // 在生成assets前触发
       compiler.hooks.emit.tap('CopyrightPlugin', (compilation) => {
         // 遍历所有输出文件
         for (const filename in compilation.assets) {
           if (filename.endsWith('.js')) {
             const content = compilation.assets[filename].source();
             // 添加版权注释
             const newContent = `/* 版权所有 © ${this.author} */n${content}`;
             compilation.assets[filename] = {
               source: () => newContent,
               size: () => newContent.length
             };
           }
         }
       });
     }
}
// 配置使用
module.exports = {
     plugins: [
       new CopyrightPlugin({ author: 'Webpack进阶开发者' })
     ]
};七、多环境配置方案
7.1 配置文件拆分
            
            
              javascript
              
              
            
          
          webpack-config/
├── webpack.common.js   # 公共配置
├── webpack.dev.js      # 开发环境配置
├── webpack.test.js     # 测试环境配置
└── webpack.prod.js     # 生产环境配置7.2 环境融合与变量注入
            
            
              javascript
              
              
            
          
          # 安装合并工具
npm install webpack-merge --save-dev
            
            
              javascript
              
              
            
          
          // webpack.common.js 公共配置
module.exports = {
     entry: './src/index.js',
     plugins: [new HtmlWebpackPlugin({ template: './public/index.html' })]
};
// webpack.prod.js 生产环境配置
const { merge } = require('webpack-merge');
const common = require('./webpack.common');
const TerserPlugin = require('terser-webpack-plugin');
module.exports = merge(common, {
     mode: 'production',
     optimization: { minimizer: [new TerserPlugin()] },
     plugins: [
       new webpack.DefinePlugin({
         'process.env.NODE_ENV': JSON.stringify('production'),
         'process.env.API_BASE': JSON.stringify('https://api.prod.com')
       })
     ]
});7.3 启动脚本配置
            
            
              javascript
              
              
            
          
          // package.json
{
     "scripts": {
       "start": "webpack serve --config webpack-config/webpack.dev.js",
       "build:test": "webpack --config webpack-config/webpack.test.js",
       "build:prod": "webpack --config webpack-config/webpack.prod.js"
     }
}八、避坑与最佳实践
8.1 常见进阶问题解决
- 
Module Federation 版本冲突 解决方案:共享依赖设置版本范围 
            
            
              javascript
              
              
            
          
          shared: {
     react: {
       singleton: true,
       requiredVersion: '^18.0.0' // 兼容18.x版本
     }
}- 
Tree Shaking 删除必要代码 解决方案:使用 /*#__PURE__*/标记纯函数
            
            
              javascript
              
              
            
          
          // 标记此函数无副作用,仅返回值有用
const utils = /*#__PURE__*/ require('./utils');