Webpack 5 在构建智能化方面做出了一系列底层调整,其中模块联邦、持久化缓存和资源模块可以被视为三个代表性方向。它们共同的目标是减少重复工作、降低配置复杂度,并让打包结果在复杂应用架构下依然保持可控。

模块联邦:让多个应用在运行时共享代码
模块联邦的提出是为了解决微前端和大型多团队协作下的公共代码共享问题。传统做法中,多个前端应用要么把公共依赖打包进各自的 bundle,导致体积膨胀;要么通过 externals 方式把公共库挂到全局,但这会破坏模块间的引用关系。模块联邦则定义了一套运行时加载协议,允许一个应用充当远程模块提供者,另一个应用在运行时动态加载这些模块。
配置上,模块联邦通过 ModuleFederationPlugin 实现。宿主应用通过 remotes 声明要引用的远程入口,远程应用通过 exposes 暴露模块。下面是一个宿主应用的配置示例。
const ModuleFederationPlugin = require('webpack/lib/container/ModuleFederationPlugin');
module.exports = {
entry: './src/index.js',
mode: 'development',
plugins: [
new ModuleFederationPlugin({
name: 'host',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
},
shared: {
react: { singleton: true, eager: true },
'react-dom': { singleton: true, eager: true },
},
}),
],
};
远程应用的配置则通过 exposes 将组件或工具模块暴露给外部使用。当宿主应用执行 import('app1/Button') 时,Webpack 会到对应的 remoteEntry.js 中查找模块定义并加载。共享依赖通过 shared 字段声明,singleton: true 确保整个运行时只有一个 React 实例,避免 Hook 状态混乱。这种方式比简单的 CDN externals 更可靠,因为模块联邦保留了完整的模块上下文。
持久化缓存:把构建中间态写入文件系统
Webpack 4 时代的缓存大多依赖 cache-loader 或 hard-source-webpack-plugin,但这些方案要么只缓存 loader 结果,要么在 Webpack 内部 API 变化时容易失效。Webpack 5 原生提供了 filesystem 类型的持久化缓存,能够将模块的处理结果、依赖关系以及 chunk 信息保存到磁盘,默认位于 node_modules/.cache/webpack 目录。
要开启持久化缓存,只需要在 webpack.config.js 中加入 cache 配置。下面是一个最小配置。
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
config: [__filename],
},
},
};
其中 buildDependencies.config 用于声明配置文件本身的变化会影响缓存有效性。这样当 webpack.config.js 发生变化时,Webpack 会自动让旧缓存失效。持久化缓存对开发环境的冷启动提升尤其明显,因为第二次启动时不需要重新解析所有依赖,而是直接从缓存反序列化模块图。对于大型单页应用,原本需要几十秒的首次构建可以降到几秒甚至更短,热更新也能更快地定位变更模块。
需要注意的是,filesystem 缓存并不总是安全,某些 loader 或插件如果带有不确定的输出或者依赖外部环境,可能会让缓存结果失效或产生不一致。这是 Webpack 5 在智能缓存策略中需要谨慎处理的边界场景。
资源模块与确定性 ID:让打包输出更稳定
Webpack 5 将 file-loader、url-loader 和 raw-loader 的功能整合为内置的资源模块,提供了 asset/resource、asset/inline、asset/source 和 asset 四种类型。例如处理 PNG 图片时,不再需要额外安装 loader,直接在规则中声明 type 即可。
module.exports = {
module: {
rules: [
{
test: /\.png$/,
type: 'asset/resource',
},
{
test: /\.svg$/,
type: 'asset/inline',
},
],
},
};
asset/resource 会把文件单独输出并返回 URL,asset/inline 会把文件内容转成 data URI 内联到代码中。内置资源模块减少了依赖数量,也让配置语义更加清晰。对于需要自定义文件名或输出路径的场景,Webpack 5 仍然支持 generator.filename 进行定制,这与旧版 loader 的 name 参数类似。
另一个容易被忽视但很重要的改进是确定性 chunk ID。在 Webpack 4 中,异步 chunk 的 ID 默认是自增的整数,构建顺序变化会导致 chunk ID 不稳定,进而影响长效缓存。Webpack 5 默认使用确定性的 ID 生成策略,使得相同内容在多次构建中产生相同的 chunk 文件名和模块 ID。这样一来,配合 HTTP 缓存或 CDN,用户只需要下载真正变化的资源。对于工程化团队而言,这减少了哈希漂移带来的缓存失效问题,也是智力创新的体现之一。
总体来看,Webpack 5 的这些新特性并不是简单的配置堆叠,而是从模块共享、缓存策略和输出稳定性三个层面重新梳理了构建工具应该具备的智能能力。理解它们之后,升级配置和优化构建流程会更有方向。