- 示例工程
【免费下载链接】module-federation-examples
Implementation examples of module federation , by the creators of module federation
本指南以module-federation-vite-svelte示例为蓝本,讲解如何基于 Vite 与 Svelte(含 TypeScript)搭建模块联邦(Module Federation)架构下的宿主应用(host)与远程应用(remote),实现跨应用动态加载 Svelte 组件并共享第三方依赖。读完本文,你将掌握@module-federation/vite插件的核心配置项(name、remotes、exposes、shareScope)、pnpm workspace 下的启动流程,以及 host 侧通过动态import()实例化 remote 组件的完整方案。
一、示例概览:Svelte host + remote 架构
module-federation-vite-svelte示例在module-federation-examples仓库中演示了一个最基础的 Svelte 模块联邦场景:一个host(宿主)应用与一个remote(远程)应用各自独立开发、独立构建,运行时由 host 从 remote 拉取remoteEntry.js并加载其暴露的 Svelte 组件。整个目录结构如下:
module-federation-vite-svelte/ ├── package.json # workspace 脚本入口(install:deps / preview 等) ├── host/ # 宿主应用,运行于 4173 端口 │ ├── vite.config.ts # federation 插件 + svelte 插件 │ └── src/App.svelte # 动态 import remote 组件并实例化 └── remote/ # 远程应用,运行于 4174 端口 ├── vite.config.ts # exposes 暴露 './remote-app' └── src/App.svelte # 被 host 消费的 Svelte 组件两个应用都是标准的 Vite + Svelte + TypeScript 模板:main.ts将App.svelte挂载到index.html的#app节点(见 host/src/main.ts 与 remote/src/main.ts),svelte.config.js统一启用vitePreprocess()预处理。差异全部集中在各自的vite.config.ts中,这正是模块联邦配置发挥作用的地方。
二、快速开始:两条命令跑通示例
原文档给出的启动步骤非常精简,从示例目录执行:
pnpm install:deps pnpm preview随后在浏览器打开http://localhost:4173/即可看到 host 应用渲染,并在页面中加载出 remote 应用暴露的组件(如上方截图所示)。
这两条命令并非空壳,它们由 module-federation-vite-svelte/package.json 中的 workspace 脚本驱动:
| 脚本 | 实际执行命令 | 作用 |
|---|---|---|
install:deps | pnpm --filter module-federation-vite-svelte-* install | 只安装 host、remote 两个子包依赖 |
postinstall:deps | pnpm --filter module-federation-vite-svelte-* run build | 安装后自动构建两个应用 |
preview | pnpm --filter module-federation-vite-svelte-* preview | 以生产构建产物启动预览服务 |
dev | pnpm --filter module-federation-vite-svelte-* dev | 开发模式(HMR)启动 |
build | pnpm --filter module-federation-vite-svelte-* build | 仅执行构建 |
仓库根目录的 pnpm-workspace.yaml 中已声明'module-federation-vite-svelte'与'module-federation-vite-svelte/*'为 workspace 包,因此pnpm --filter可以精确选中 host 与 remote。两个子包的package.json脚本也保持一致:dev、build、preview分别绑定各自端口——host 为4173(host/package.json),remote 为4174(remote/package.json)。
注意:原文档中的
pnpm preview会同时启动 host(4173)与 remote(4174)两个服务。若你只希望单独调试 remote,可进入remote目录执行pnpm dev或pnpm preview;反之,host 单独启动时仍会尝试从http://localhost:4174/remoteEntry.js拉取 remote,因此联调时务必先保证 remote 已就绪。
三、remote 侧:如何暴露一个 Svelte 组件
remote 应用负责“生产”模块,核心配置集中在 remote/vite.config.ts:
import { federation } from '@module-federation/vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; import { defineConfig } from 'vite'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [ svelte(), federation({ filename: 'remoteEntry.js', name: 'remote', exposes: { './remote-app': './src/App.svelte', }, remotes: {}, }), ], build: { target: 'chrome89', }, });各配置项含义如下:
name: 'remote':联邦模块的唯一标识,host 通过该名称引用此 remote。filename: 'remoteEntry.js':remote 的入口清单文件名,构建后由 host 的entry地址加载。exposes:对外暴露的模块映射表。'./remote-app'是暴露的逻辑键名,'./src/App.svelte'是实际文件路径。host 侧动态import("remote/remote-app")中的remote-app即对应此键。remotes: {}:remote 自身不消费任何其他联邦模块,因此留空。build.target: 'chrome89':将构建产物目标定为 Chrome 89 及以上,保证现代浏览器语法兼容;在 Vite 的 module federation 场景下,该目标同时也约束了产物能被 host 端正常解析。
构建后,remote 会在根路径产出remoteEntry.js,即 host 需要拉取的入口文件。
四、host 侧:声明 remote 并配置共享作用域
host 应用负责“消费”模块,配置位于 host/vite.config.ts:
import { federation } from '@module-federation/vite'; import { svelte } from '@sveltejs/vite-plugin-svelte'; import { defineConfig } from 'vite'; // https://vitejs.dev/config/ export default defineConfig({ plugins: [ svelte(), federation({ name: 'host', remotes: { remote: { type: 'module', name: 'remote', entry: 'http://localhost:4174/remoteEntry.js', entryGlobalName: 'remote', shareScope: 'default', }, }, exposes: {}, filename: 'remoteEntry.js', }), ], build: { target: 'chrome89', }, });host 端需要重点理解以下几个字段:
remotes.remote:声明一个名为remote的远程联邦模块,键名remote将作为 host 代码中import("remote/...")的命名空间前缀。type: 'module':指定 remote 产物以 ESM 模块形式加载,这是 Vite 场景下@module-federation/vite推荐的加载类型。entry: 'http://localhost:4174/remoteEntry.js':remote 入口文件的完整 URL。开发与预览模式下,remote 的 4174 端口必须与本地址一致。entryGlobalName: 'remote':与 remote 的name对应,用于运行时全局标识。shareScope: 'default':指定共享作用域名称。default是联邦运行时默认的共享 scope,host 与 remote 只有处于同一共享 scope 时,第三方依赖(如 rxjs)才能被正确去重与共享。exposes: {}/filename:host 自身不暴露任何模块,但仍保留remoteEntry.js的默认输出名称(若 host 未来也要被其他应用消费,可在此补充exposes)。
由于 host 与 remote 均设置了build.target: 'chrome89',两者产物的语法基线保持一致,避免了跨应用加载时的兼容性断层。
五、跨应用组件加载:动态 import 与手动实例化
host 消费 remote 组件的方式极具 Svelte 特色——通过动态import()拿到组件类后,手动new实例化并指定挂载目标。核心代码位于 host/src/App.svelte:
<script lang="ts"> import { of, tap } from 'rxjs'; let remoteAppTarget; (async () => { //@ts-ignore const app = await import("remote/remote-app"); new app.default({ target: remoteAppTarget }); })(); of('emit') .pipe(tap(() => console.log("I'm RxJs from host"))) .subscribe(); </script> <div class="host"> <div class="card">…I'm the host app…</div> </div> <!-- 将 DOM 节点绑定给 remote 组件作为挂载目标 --> <div bind:this={remoteAppTarget} />这里有两个关键机制:
- 动态命名空间导入:
import("remote/remote-app")中的remote对应 host 配置里remotes的键名,remote-app对应 remote 配置里exposes的键名'./remote-app'。运行时该语句会被联邦运行时替换为对http://localhost:4174/remoteEntry.js的按需加载。 bind:this+new app.default():Svelte 组件实例化时需要传入target(挂载 DOM 节点)。host 用bind:this={remoteAppTarget}把模板中的<div>节点引用交给变量,随后在异步回调中执行new app.default({ target: remoteAppTarget }),从而把 remote 的App.svelte渲染到 host 页面里。这也是 Svelte 生态中消费联邦组件的主流方式——不同于 React 的 JSX 直接渲染,Svelte 的编译器产物天然以“组件构造器 + target”的形式挂载。
remote 侧的 remote/src/App.svelte 则是一个自带样式的独立卡片组件,同时也在自身挂载时通过 rxjs 输出"I'm RxJs from remote"日志,用于验证依赖共享链路。
六、依赖共享实践:rxjs 的双端验证
该示例的妙处在于通过rxjs演示了第三方依赖如何在 host 与 remote 之间共享:
- host 的 App.svelte 中
import { of, tap } from 'rxjs'并订阅,控制台输出"I'm RxJs from host"; - remote 的 App.svelte 同样引入 rxjs,控制台输出
"I'm RxJs from remote"; - 两个子包的 package.json 都将
rxjs: ^7.6.0声明在dependencies中,且版本一致。
配合 host 配置中的shareScope: 'default',联邦运行时会在加载 remote 时优先复用 host 已实例化的 rxjs 单例,避免同一依赖在页面中被重复打包、重复执行。打开浏览器控制台即可同时看到两条日志,这是验证“依赖共享是否生效”最直观的检查点。
七、运行环境与版本基线
示例当前的依赖基线(以两个子包 package.json 为准):
@module-federation/vite1.11.0(联邦插件)vite^5.4.8svelte^4.2.19@sveltejs/vite-plugin-svelte^3.1.2typescript^5.5.3、svelte-check^4.0.4
TypeScript 配置统一继承@tsconfig/svelte,并开启allowJs/checkJs(见 host/tsconfig.json),使.svelte与.js文件都能获得类型检查。host 代码中import("remote/remote-app")前的//@ts-ignore注释,正是因为在静态类型层面 TypeScript 无法感知联邦运行时动态注册的模块命名空间——这是当前 Vite 联邦方案的常见类型局限,可通过自定义模块声明(如declare module 'remote/*')进一步缓解。
八、排错与调试建议
- 打开 4173 一片空白:检查 remote 是否已在 4174 端口正常提供
remoteEntry.js。可先单独访问http://localhost:4174/remoteEntry.js确认文件可拉取。 - 控制台报模块加载失败:核对 host 配置中
entry的端口号是否与 remote 实际预览端口一致(本示例固定为 4174)。 - 依赖重复加载:确认 host 与 remote 的
shareScope名称一致(均为default),且 rxjs 版本声明兼容,否则联邦运行时不会走共享路径。 - 开发模式调试:在
host/remote目录分别执行pnpm dev,可借助 Vite HMR 即时调试两端源码;pnpm preview则更贴近生产构建产物下的真实表现。
九、小结
module-federation-vite-svelte用最精简的双应用结构,完整覆盖了 Vite + Svelte 模块联邦的关键链路:remote 通过exposes暴露 Svelte 组件,host 通过remotes.entry声明远程入口,并以“动态import()+new Component({ target })”的方式完成跨应用渲染;同时以 rxjs 为例验证了shareScope: 'default'下的依赖共享机制。这套模式同样可参考仓库中module-federation-vite-react、module-federation-vite-vue3、module-federation-vite-solid等姊妹示例(配置结构高度一致,仅框架插件与 shared 声明不同),是理解模块联邦在 Vite 生态落地的理想起点。
- 示例工程
【免费下载链接】module-federation-examples
Implementation examples of module federation , by the creators of module federation
相关推荐
使用 Vite 构建 React 模块联邦应用:module-federation-examples 中 host 与 remote 实战指南
使用 Vite 构建 React 模块联邦应用:module federation examples 中 host 与 remote 实战指南 module f
示例工程module-federation-examples basic-host-remote:用 Modern.js 搭建最小 Host-Remote 模块联邦示例
module federation examples basic host remote:用 Modern.js 搭建最小 Host Remote 模块联邦示例
示例工程Module Federation 实战:用 Vite + Angular 构建 host/remote 微前端(module-federation-vite-angular 示例解析)
Module Federation 实战:用 Vite + Angular 构建 host/remote 微前端(module federation vite
示例工程
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考