Esmx 模块链接实战:供给方、消费方、组合方三种角色如何协作?
Esmx 模块链接实战:供给方、消费方、组合方三种角色如何协作?
【免费下载链接】genesisNext-generation micro-frontend framework based on ESM, sandbox-free with zero runtime overhead, supporting multi-framework hybrid development项目地址: https://gitcode.com/gh_mirrors/genesis8/genesis
Esmx 是一个基于 ESM 标准的下一代微前端框架,以"无沙箱、零运行时开销、支持多框架混合开发"著称。而**模块链接(Module Linking)**正是它实现跨应用代码共享的核心能力:多个独立构建的应用之间,可以像使用本地模块一样安全地共享代码,全程不引入任何额外的运行时库。本文用最小配置带你理解模块链接中的三种协作角色——供给方、消费方、组合方,以及它们之间"接线"是如何被自动推导出来的。
一图看懂:多框架子应用如何组合成一个平台
在动手之前,先看 Esmx 官方示例 Hub 的最终效果:一个页面里同时承载 Vue 2/3、React、Preact、Solid、Svelte、Lit 等 7 种框架、3 种打包工具构建的 15 个子应用,全部通过"一个 import map"统一管理,这正是模块链接三种角色协作的直观成果。
单个子应用(如 React 19 计数器)则以独立微应用的形式运行在统一平台中,互不干扰:
三种协作角色分别承担什么职责?
模块链接的协议事实全部写在package.json的一个esmx字段里,恰好四个可选子字段:
| 字段 | 含义 |
|---|---|
entry | 框架入口(client / server),库模块可省略 |
exports | 带逻辑名的子路径映射,消费方永远看不到物理路径 |
provides | 本模块为消费方再导出的第三方包列表 |
uses | 你所消费的模块名列表,数组顺序有意义 |
三种角色覆盖所有工程场景,而且每份声明都只是"本地知识"——你可以在对其他模块一无所知的情况下写出来。
角色一:供给方(共享平台包)
供给方是提供共享能力的"基座",比如统一封装 UI、状态管理与公共依赖的shared包。它的exports暴露的是逻辑名而非物理路径,provides则声明了它愿意为下游再导出的第三方包(如vue、@esmx/router):
{ "name": "shared", "version": "3.2.1", "esmx": { "exports": { "./ui": "./src/ui/index.ts", "./store": { "client": "./src/store.client.ts", "server": "./src/store.server.ts" } }, "provides": ["vue", "@esmx/router"] } }消费方只需import 'shared/ui',即使供给方重命名了源文件,也不是破坏性变更。仓库中的 ssr-micro-shared/package.json 就是这样一个真实供给方示例。
角色二:消费方 + 供给方(功能远程)
大多数业务模块身兼两职:既消费共享平台的能力,又向更上层的宿主提供自己的业务导出。比如购物车模块cart,它uses了shared,同时exports出自己的./widget:
{ "name": "cart", "version": "1.8.0", "dependencies": { "shared": "^3.0.0" }, "peerDependencies": { "vue": "^3.4.0" }, "esmx": { "exports": { "./widget": "./src/cart-widget.ts" }, "uses": ["shared"] } }注意这里没有手写的 imports 映射,也没有逐 specifier 的接线;版本范围就放在 npm 本来就放的地方——dependencies,并在构建时对照实际版本自动校验。
角色三:组合方(宿主)
宿主是聚合一切的最终应用,它只声明自己依赖了谁,其余交给模块链接的传递规则:
{ "name": "host", "version": "2.0.0", "dependencies": { "shared": "^3.0.0", "cart": "^1.5.0" }, "esmx": { "uses": ["shared", "cart"] } }uses是传递的:如果cartusesshared,那么 usescart的宿主会自动通过链条获得shared的供给。业务应用只声明一行,对链条深度毫不知情。参考真实宿主 ssr-micro-hub/package.json,它的uses列出了一长串子应用,却没有任何手写接线。
接线如何被推导?两条规则取代所有手写映射
模块链接的精髓在于"零接线",由两条规则完成:
合并规则:supply(M) = merge(supply(uses[0]), …, supply(uses[n]), M.provides)——后面的条目覆盖前面的,模块自己的provides是隐含的最后一个元素。当两个模块供给同一个包时,uses数组的顺序决定谁赢(按从通用到具体排列,具体层胜出)。选举是逐 major 版本进行的,共存的 major(如 Vue 2 和 Vue 3)是互相隔离的孤岛,各有自己的赢家。
查找规则:打包器遍历你的代码时逐 specifier 判断——裸 specifier 出现在合并后的供给表里就外部化并接到赢家;哪里都找不到,则打包成自己的副本,由逐模块的 import-map scope 自动隔离。因此单实例共享是固有的,多版本共存也不需要额外词汇。
这套逻辑在源码中有清晰实现:module-link/config.ts 负责外部化与入口配置,module-link/manifest-plugin.ts 构建包含exports与chunks的 manifest.json,入口统一在 module-link/index.ts。
用 esmx validate 免构建校验整张图
改完声明后,无需执行完整构建即可验证所有接线是否成立。esmx validate是整个解析过程的 dry run——覆盖挂载遍历、版本检查、供给合并、导出检查:
esmx validate # 人类可读报告 esmx validate --json # 机器可读信封,适合 CI / Agent只有出现 error 级诊断才以非零码退出;仅有警告则退出 0。完整诊断分类(E_NOT_LINKED、E_VERSION、E_SCHEMA、W_MULTI_MAJOR等)可查阅官方文档 module-linking.md 与核心实现 packages/core/src/module-config.ts。
实战:Vue 2 与 Vue 3 如何在同一平台共存?
多版本共存是模块链接最亮眼的场景。一个共享基座并排供给两个 major 的 Vue,每个业务应用只声明自己的版本范围,解析器自动把它们接到匹配的 major,全程没有任何手写 imports:
- 共享基座
shared:provides: ["vue", "vue2", "@esmx/router"],其中vue2通过 npm 别名npm:vue@^2.7.0引入,每个 major 是独立的选举分组; - Vue 3 应用:声明
peerDependencies: { "vue": "^3.5.0" },uses: ["shared"],只导出自己的路由配置; - Vue 2 应用:声明
"vue": "npm:vue@^2.7.0",同样只写一行uses; - 聚合宿主
host:uses: ["shared", "vue2-app", "vue3-app"],每个子应用一行,组合子应用的单一路口。
构建好子应用后运行esmx validate --json,即可确认整张依赖图能解析。
模块链接 vs Module Federation:有何不同?
| 对比项 | Esmx 模块链接 | Module Federation |
|---|---|---|
| 运行时 | 原生 ESM + Import Maps | Webpack/Rspack 运行时容器 |
| 开销 | 零额外运行时 | Federation 运行时 + 共享作用域协商 |
| SSR | 一等公民,SEO 友好 | 需额外配置,历史上较脆弱 |
| 版本 | 显式 provider,单一所有者 | 运行时共享作用域协商 |
由于链接基于浏览器自身的模块系统,没有沙箱、没有私有加载器,同一份import在浏览器、SSR 与测试中都表现一致。
想亲自体验?
克隆仓库后即可在本地跑起包含 15 个子应用的完整示例:
git clone https://gitcode.com/gh_mirrors/genesis8/genesis进入examples/micro-app目录,观察ssr-micro-shared(供给方)、各框架子应用(消费方 + 供给方)与ssr-micro-hub(组合方)三者之间如何用最少的声明完成最复杂的协作。理解了这三种角色,你就掌握了 Esmx 微前端架构的核心心智模型。
【免费下载链接】genesisNext-generation micro-frontend framework based on ESM, sandbox-free with zero runtime overhead, supporting multi-framework hybrid development项目地址: https://gitcode.com/gh_mirrors/genesis8/genesis
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考