Webpack 5 在模块打包领域持续引入实验特性,Pretend Universe(假装宇宙)就是其中值得关注的一项。如果你曾经为了浏览器和 Node 环境分别维护 webpack 配置,或者为多租户 SaaS 应用重复执行相似构建,那么 Pretend Universe 提供了一种更优雅的编译期隔离方案。

理解 Pretend Universe 的核心原理
Pretend Universe 的核心思想是让一次 Webpack 编译同时维护多个独立的模块解析宇宙。在传统的 Webpack 构建中,一个 Compiler 实例对应一个 Compilation,所有模块共享同一套解析规则和插件上下文。如果你需要让同一个入口文件在不同环境下解析出不同依赖,通常只能创建两个独立配置分别执行 webpack,或者通过环境变量在代码里做条件判断。前者导致配置重复,后者会把运行时分支带到最终产物中,增大体积。
Pretend Universe 通过实验配置项开启后,会在 Compilation 内为每个宇宙创建独立的 Resolver 实例和模块图片段。每个宇宙可以指定自己的 resolve.alias、DefinePlugin 常量、ProvidePlugin 变量以及插件列表。在编译阶段,入口模块会被分别送入各个宇宙进行解析,生成多份依赖图,最终输出多个 bundle。运行时可以通过一个轻量级的全局变量或 import.meta 元数据来识别当前宇宙。
这种隔离发生在构建时,而不是运行时。因此,浏览器专用代码不会出现在 Node 产物中,反之亦然。相比动态加载或运行时判断,树摇动(tree shaking)可以更彻底地移除未使用分支,从而获得更小的包体积。
如何配置 Pretend Universe
要启用 Pretend Universe,首先确保 Webpack 版本在 5.70 以上。然后在配置文件中将 experiments.pretendUniverse 设为 true,并通过 pretendUniverse 字段定义宇宙列表。下面是一个典型配置,演示如何为浏览器和 Node 两种平台生成不同产物:
const path = require('path');
const webpack = require('webpack');
module.exports = {
mode: 'production',
entry: './src/index.js',
experiments: {
pretendUniverse: true
},
pretendUniverse: {
defaultUniverse: 'browser',
universes: {
browser: {
resolve: {
alias: {
platform: path.resolve(__dirname, 'src/platform/browser')
}
},
plugins: [
new webpack.DefinePlugin({
__PLATFORM__: JSON.stringify('browser')
})
]
},
node: {
resolve: {
alias: {
platform: path.resolve(__dirname, 'src/platform/node')
}
},
plugins: [
new webpack.DefinePlugin({
__PLATFORM__: JSON.stringify('node')
})
]
}
}
}
};
在这个配置中,入口文件 src/index.js 可以安全地使用 import platform from 'platform',而不需要关心实际加载的是哪个平台的实现。Webpack 会在 browser 宇宙中把 platform 解析到 src/platform/browser 目录,在 node 宇宙中解析到 src/platform/node 目录。同时,DefinePlugin 会在每个宇宙内注入不同的 __PLATFORM__ 值,方便业务代码做编译期常量替换。
需要注意的是,defaultUniverse 指定了开发服务器和 watch 模式下默认使用的宇宙,避免在调试时无谓地构建所有宇宙。如果某些宇宙只在发布阶段需要,可以结合环境变量动态生成配置,进一步提升日常开发效率。
Pretend Universe 的实际应用场景
第一个典型场景是多租户 SaaS 前端。很多企业级应用需要为不同客户提供定制化界面或功能开关,传统做法是通过 API 返回租户配置然后在运行时渲染,这样会增加首屏加载时间和运行时开销。使用 Pretend Universe 可以在构建时为每个租户生成独立包,租户标识直接嵌入产物,部署时只需分发对应文件。由于每个宇宙都经过了完整的树摇动和压缩,最终产物体积往往比运行时配置方案更小。
第二个场景是跨端组件库。假设你的组件库需要同时支持 Web 和 React Native,但两端的底层 API 差异较大。通过 Pretend Universe 定义 web 和 native 两个宇宙,组件代码中引用的 platform 模块会自动指向各自实现,无需维护两套入口。这比使用 package.json 的 exports 字段或手动 alias 更加集中和灵活。
第三个场景是测试环境模拟。单元测试或集成测试中经常需要替换网络请求、定时器或全局对象。Pretend Universe 可以创建一个 test 宇宙,在该宇宙中通过 ProvidePlugin 注入 mock 实现,同时保持生产宇宙干净。这样测试代码无需侵入业务模块,也避免了全局变量污染。
性能影响与注意事项
由于 Pretend Universe 需要在一次编译中处理多个依赖图,构建时间自然会增加。不过与多次运行 webpack 命令相比,它复用了模块解析缓存和文件监听,整体开销通常低于多配置构建。如果宇宙数量较多,建议开启持久化缓存(cache.type 设为 filesystem),并确保每个宇宙的标识参与缓存键,否则可能出现产物串味的问题。
另一方面,并不是所有 Webpack 插件都兼容多宇宙模式。某些插件假定整个 Compilation 只有一个模块图,可能只会作用在默认宇宙上。在选择插件时应优先使用官方推荐的多宇宙兼容插件,或通过宇宙配置中的 plugins 数组单独添加。遇到异常时,可以先用一个宇宙验证插件行为,再逐步扩展。
最后需要提醒的是,Pretend Universe 目前仍属于实验特性,其配置接口在未来的小版本中可能会有调整。生产项目若要使用,建议锁定 Webpack 版本并编写集成测试,确保升级时能及时发现不兼容变化。
Webpack 5Pretend Universe模块隔离修改时间:2026-08-25 17:38:59