先说结论:Webpack 5 官方从未发布过名为 Ghostly Universe(鬼魂宇宙)的特性,这个说法在 Webpack 官方文档和 GitHub 仓库中都查不到任何出处,大概率是网络传言或者某篇博文的虚构命名。不过既然大家是冲着 Webpack 5 新特性来的,这篇文章就把 Webpack 5 真正值得关注的几个重大更新讲透,包括持久化缓存、模块联邦、Tree Shaking 增强和资源模块,这些才是实打实能提升构建体验和运行性能的东西。

持久化缓存:二次构建速度提升的秘密
Webpack 4 时代的缓存只有 cache: true 这一个开关,它只能在内存中缓存模块,构建进程一结束缓存就没了。也就是说每次重新启动构建,所有模块都要重新走一遍完整的编译流程,大中型项目的冷启动时间经常以分钟计,这是很多团队抱怨构建慢的根本原因之一。
Webpack 5 引入了基于文件系统的持久化缓存,配置方式非常简单:
module.exports = {
cache: {
type: 'filesystem',
buildDependencies: {
// 推荐把配置文件本身作为构建依赖,配置一变缓存自动失效
config: [__filename]
}
}
};开启之后,Webpack 会把每个模块的处理结果缓存到 node_modules/.cache/webpack 目录下。第一次构建可能比不开缓存还慢一点,因为要写入缓存文件,但从第二次构建开始,只要源代码和相关依赖没变,模块就会直接从磁盘读取,跳过解析、转换、优化等大量步骤。在实际项目中,二次构建速度提升百分之七八十是很常见的。
需要注意的是,缓存失效的判定依赖文件的完整性哈希。如果你修改了 babel.config.js、postcss.config.js 这类影响编译结果的配置文件,但 Webpack 没有感知到,就可能读到脏缓存。解决办法就是像上面那样把这些配置文件显式声明到 buildDependencies 中,保证配置变更时缓存自动作废。
模块联邦:微前端架构的官方答案
模块联邦(Module Federation)是 Webpack 5 里最具话题性的新特性,它允许多个独立构建、独立部署的应用在运行时共享代码。听起来有点抽象,举个实际场景:主应用和子应用是两个团队分别开发、分别部署的项目,子应用需要用到主应用封装的按钮组件和工具函数,传统做法要么复制代码,要么发布 npm 包再各自安装,两者都有维护成本。有了模块联邦,子应用可以直接在运行时加载主应用暴露出来的模块。
提供方(宿主应用)的配置:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'hostApp',
filename: 'remoteEntry.js',
exposes: {
'./Button': './src/components/Button.vue',
'./utils': './src/utils/index.js'
},
shared: {
vue: { singleton: true },
lodash: { singleton: true }
}
})
]
};消费方(远程应用)的配置:
const { ModuleFederationPlugin } = require('webpack').container;
module.exports = {
plugins: [
new ModuleFederationPlugin({
name: 'remoteApp',
remotes: {
hostApp: 'hostApp@https://cdn.ipipp.com/host/remoteEntry.js'
},
shared: {
vue: { singleton: true }
}
})
]
};配置完成后,远程应用里就可以直接 import Button from 'hostApp/Button',和引入本地模块几乎无差别。其中的 shared 配置很关键,声明为 singleton 的依赖在整个页面只会加载一份,避免主应用和子应用各自打包一份 Vue 导致的实例冲突和体积浪费。当然模块联邦也不是银弹,它要求各应用对共享依赖的版本做一定的兼容约定,运行时动态加载也意味着网络请求的时序需要妥善处理,团队在选型时还是要结合自身规模来评估。
Tree Shaking 与代码体积优化
Webpack 5 对 Tree Shaking 做了一轮深度增强,主要增加了对嵌套导出、模块串联分析以及部分 CommonJS 语法的支持。以前一些工具库虽然标注了 ES Module 导出,但内部写法导致删除不干净,新版本的分析器能识别更多场景。比较值得一提的是全新的导出粒度分析能力:
import { map } from 'lodash-es';
// Webpack 5 能识别下面这行只是属性读取,不会阻止 Tree Shaking
const mapFn = map;
// 但如果整体引用命名空间,摇树效果会大打折扣
import * as lodash from 'lodash-es';
const result = lodash.map([1, 2, 3], n => n * 2);另外 Webpack 5 移除了一些长期处于废弃状态的语法分析,比如对 import 断言混用 CommonJS 的一些宽松处理,这让打包器对模块结构的理解更严格,副作用判定更精确。配合 sideEffects: false 的包标识,最终产物的体积往往比 Webpack 4 小上不少。
资源模块处理与升级注意事项
Webpack 5 内置了资源模块(Asset Modules),用来替代长期以来需要 file-loader、url-loader、raw-loader 组合才能完成的工作。现在一条规则就能搞定:
module.exports = {
module: {
rules: [
{
test: /\.(png|jpg|gif|svg)$/,
type: 'asset',
parser: {
dataUrlCondition: {
// 小于 8kb 转成 base64 内联,超过则输出单独文件
maxSize: 8 * 1024
}
}
}
]
}
};除了 asset 这种自动判断的模式,还有 asset/resource(始终输出文件)、asset/inline(始终内联)和 asset/source(导出源码字符串)三种精确模式可选。升级时记得删掉旧的 loader 配置,避免规则冲突。
关于升级本身,有几个坑需要提前知道。一是 Node.js 版本要求提升到 10.13 以上,太老的环境直接跑不起来;二是 node polyfill 不再自动注入,浏览器端代码如果引用了 Node 核心模块,需要手动安装对应的 polyfill 或者调整 resolve.fallback 配置;三是部分老版本插件与 Webpack 5 不兼容,升级前先把 html-webpack-plugin、terser-webpack-plugin 等常用插件升到主流版本。把这些准备工作做完,再配合前面讲的持久化缓存,构建体验的提升会非常明显。至于那个所谓的鬼魂宇宙特性,就当个段子听听吧,真正的好东西都在官方文档里。
Webpack 5Ghostly Universe模块联邦修改时间:2026-09-03 14:35:25