资讯动态

Vue CLI 微前端实战:基于 Module Federation 的 Vue 2 多应用组合与依赖共享

发布时间:2026/10/15 9:55:07 来源:尧图企业网站定制
示例工程【免费下载链接】module-federation-examplesImplementation examples of module federation , by the creators of module federation项目地址https://gitcode.com/gh_mirrors/mo/module-federation-examples点击查看免费下载本指南以 module-federation-examples 仓库中的 vue-cli/readme.md 为核心剖析一个以 Vue CLIVue 2构建的微前端示例一个 Consumer 壳应用如何组合来自 Core、Other 两个独立构建、独立部署的前端应用的组件。阅读完本文你将掌握在 Vue CLI 工程中接入module-federation/enhanced插件、配置remotes/exposes/shared三项核心能力、实现跨应用组件导入与依赖共享以及完成开发、构建、静态托管与端到端验证的完整实战链路。一、示例总体架构Consumer / Core / Other 三应用分工仓库中的vue-cli示例是一个典型的「壳 组件源 独立功能模块」三层结构三个应用由根目录 vue-cli/package.json 通过 pnpm workspaces 统一管理应用目录角色定位端口Consumervue-cli/consumer主应用 / 壳 / 根模块负责组合远程组件8080Corevue-cli/core被复用的通用组件源Button、Section9000Othervue-cli/other被 Consumer 导入的另一独立应用含自身业务行为9001原文档对三者的定位描述非常精炼「Consumer主应用、壳、根模块Core被使用的组件Other被导入进 Consumer 的另一个应用」。对应到源码consumer/src/App.vue 是唯一承担「编排」职责的入口它同时从 Core 拉取Button、Section从 Other 拉取MainComponent而 Core 与 Other 各自拥有独立的App.vue可以单独运行、单独构建——这正是微前端「独立开发、独立部署、组合呈现」的核心特征。二、快速上手开发、构建与产物运行原文档给出了三条最核心的命令序列结合根目录 vue-cli/package.json 的脚本可以还原出完整的运行链路。2.1 安装依赖在仓库根目录或vue-cli目录下执行yarn由于三个应用被声明为同一 workspaces./consumer、./core、./other依赖会被统一安装、统一提升保证三端使用的 Vue 版本一致这是后续依赖共享能够成立的前提之一。2.2 开发模式运行带热更新yarn serve根脚本将其翻译为pnpm --filter vue-cli/* --parallel serve即并行启动三个应用的vue-cli-service serve见 consumer/package.json 等三个子应用的serve脚本。启动后Consumer 默认运行在http://localhost:8080/其 vue.config.js 中publicPath即为该地址Core 的devServer.port固定为 9000见 vue-cli/core/vue.config.jsOther 的devServer.port固定为 9001见 vue-cli/other/vue.config.js。2.3 生产构建yarn build对应pnpm --filter vue-cli/* build三个应用分别产出各自的dist目录。2.4 运行构建产物pnpm run start对应根脚本pnpm --filter vue-cli/* --parallel start。三个子应用的start脚本均使用http-server对dist目录做无缓存静态托管-c-1表示禁用缓存端口分别与开发端口一致8080 / 9000 / 9001。这意味着示例同时演示了「开发期动态拉取远程组件」与「生产期静态部署后仍可跨源组合」两种形态。三、核心配置逐项拆解remotes、exposes 与 shared三个应用均通过module-federation/enhanced包提供的ModuleFederationPlugin接入统一采用module-federation/enhanced2.1.0 版本见各子应用 package.json 的 devDependencies。三份 vue.config.js 中的公共选项包括experiments: { asyncStartup: true }开启异步启动shareStrategy: loaded-first依赖共享策略为「先加载者优先」filename: remoteEntry.js对外暴露的远程入口文件名shared: require(./package.json).dependencies将本应用的全部运行时依赖声明为共享依赖。下面分别看三端的不同职责。3.1 Consumer通过 remotes 声明远程依赖consumer 的 vue.config.js 是理解「壳应用如何找到远端」的钥匙new ModuleFederationPlugin({ experiments: { asyncStartup: true }, name: consumer, shareStrategy: loaded-first, filename: remoteEntry.js, remotes: { core: corehttp://localhost:9000/remoteEntry.js, other: otherhttp://localhost:9001/remoteEntry.js, }, shared: require(./package.json).dependencies, }),remotes中的每一项都遵循名称协议://主机:端口/remoteEntry.js的约定core对应 Core 应用暴露的远程入口http://localhost:9000/remoteEntry.jsother对应 Other 应用的http://localhost:9001/remoteEntry.js。此外还设置了optimization.splitChunks: false关闭代码分包避免远程入口与共享块在跨应用加载时产生路径不一致的问题。publicPath被显式写为绝对地址http://localhost:8080/保证 Consumer 自身资源可被远程引用。3.2 Core通过 exposes 暴露可复用组件core 的 vue.config.js 展示了远端侧的核心配置new ModuleFederationPlugin({ experiments: { asyncStartup: true }, name: core, shareStrategy: loaded-first, filename: remoteEntry.js, library: { type: var, name: core }, exposes: { ./Button: ./src/components/Button, ./Section: ./src/components/Section, }, shared: require(./package.json).dependencies, }), devServer: { port: 9000, headers: { Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST, PUT, DELETE, PATCH, OPTIONS, Access-Control-Allow-Headers: X-Requested-With, content-type, Authorization, }, },要点name: core与library: { type: var, name: core }配合使远程入口以全局变量core的形式暴露供运行时按约定取用exposes将两个通用组件./Button、./Section映射为可被远程引用的模块路径即前面remotes配置中的core/Button、core/SectiondevServer.headers显式开启跨域Access-Control-Allow-Origin: *这是浏览器环境下跨端口加载远程入口的必要条件。3.3 Other暴露一个带业务行为的独立应用other 的 vue.config.js 结构与 Core 几乎一致区别在于只暴露一个模块exposes: { ./MainComponent: ./src/components/MainComponent, },端口为 9001同样配置了跨域头。注意 Other 自身也有完整的 App.vue即它可以作为独立应用单独访问同时又能把MainComponent作为远程模块提供给 Consumer——一个应用同时具备「独立运行」与「被组合」的双重身份这正是模块联邦相对传统 iframe/代理方案的典型优势。四、组件级组合Consumer 如何拉取并渲染远程组件consumer/src/App.vue 中并未静态import任何远程组件而是全部采用动态导入components: { Button: () import(core/Button), Section: () import(core/Section), MainComponent: () import(other/MainComponent), },这里的core/Button之所以能被解析正是因为上一节中remotes.core与 Core 的exposes[./Button]构成了完整的映射链。模板层的组合方式同样值得关注Section ButtonButton imported from /core/Button br / Im inside the Section component loaded from /core, but my text is defined in /consumer /SectionSection与Button都来自远端 Core但插槽内容slot由 Consumer 注入——微前端组合在这里表现为「结构由远端提供、内容由壳端编排」的灵活形态。对应地core/src/components/Button.vue 通过slot接收外部文本core/src/components/Section.vue 同样定义slot /并提供基础样式border: 1px solid black; padding: 10px。Other 的MainComponent则演示了「远程组件自带完整业务行为」其源码 other/src/components/MainComponent.vue 内置了数据请求逻辑——点击按钮会请求https://jsonplaceholder.typicode.com/todos/1并通过AbortControllerPromise.race实现了 1 秒超时兜底超时后回退到内置FALLBACK_DATA组件销毁时beforeDestroy主动清理未完成的请求。这说明微前端拆分的边界可以是「一个具备完整生命周期与独立职责的功能块」而不仅仅是展示型组件。五、依赖共享shared 选项与 UI 组件库共享原文档特别强调「项目包含bootstrap.js文件以及 vue 配置中的shared选项意味着你可以导入任意 UI 组件库uikit或其他库并在微前端之间共享它们」。5.1 shared 的声明方式三个应用的 vue.config.js 中都写了同一行shared: require(./package.json).dependencies,以 consumer/package.json 为例其dependencies为core-js与vue^2.7.16。将整个dependencies对象直接透传给shared意味着「应用声明的每个运行时依赖都参与共享协商」当一个依赖在多个联邦应用中出现时Module Federation 运行时会在它们之间挑选一个副本供各方复用从而避免 Vue、core-js 等库被重复下载和重复初始化。实践中若想共享某个 UI 库如 Element UI 等只需把它放进各自应用的dependencies再配合shared配置即可。5.2 shareStrategy: loaded-first 的含义三份配置都显式设置了shareStrategy: loaded-first即共享协商采用「先加载者优先」策略在页面加载过程中先完成初始化的应用所携带的共享依赖版本会成为各方共用的版本。这是区别于「版本回退/多副本」策略的一种更轻量、更确定的行为适合对依赖版本一致性要求较高的场景。5.3 关于 bootstrap.js 与 asyncStartup原文档提到项目存在bootstrap.js文件。需要说明的是在当前仓库的vue-cli目录中并未找到实际的bootstrap.js文件搜索仅命中文档本身从源码结构看该示例是通过experiments: { asyncStartup: true }这一开关实现等效能力的。其原理与社区常见的bootstrap.js模式一致把入口逻辑与共享依赖的加载解耦让应用在「共享依赖就绪之后」再执行真正的启动逻辑从而规避入口脚本过早执行导致的共享模块未就绪问题。从 consumer/src/main.js 可以看到Consumer 的启动代码new Vue({...}).$mount(#app)与远程组件声明是分离的这种结构正是异步启动模式能够成立的形态基础。六、端到端验证e2e 测试如何证明三应用组合正确仓库为示例配套了 Playwright 端到端测试配置文件为 vue-cli/playwright.config.tswebServer.command为pnpm serve即测试前自动拉起三个应用baseURL指向http://localhost:8080Consumer测试用例目录为 vue-cli/e2e/tests。三个测试文件分别从不同角度验证组合正确性consumerAppChecks.spec.ts打开 Consumer8080断言 Core 导入区域的标题与描述可见并借助compareInfoBetweenHosts在 Consumer8080与 Core9000、Other9001之间比对同名组件的渲染结果是否一致例如「Consumer 中的 Button 文本与 Core 本地 Button 文本是否一致」「点击后两边是否出现相同代码块与弹窗」commonChecks.spec.ts对 8080 / 9000 / 9001 三个宿主做通用性校验包括「点击后拉取到代码块、刷新后消失」「核心区块与按钮可见且可用」等otherAppChecks.spec.ts单独验证 Other 应用9001的弹窗行为即远端组件自身的行为能力在独立运行时同样成立。其中 methods.ts 封装的checkCodeTagAppearance还验证了一个微前端场景下的典型交互闭环点击「Click to fetch from FakeApi」→ 出现alert弹窗与 JSON 代码块 → 刷新页面后状态被正确重置组件卸载数据不复现。这套测试既覆盖了跨应用渲染一致性也覆盖了远程组件的行为正确性是复制该示例到自有项目后可参考的验证范式。七、小结与落地建议架构层面以 Consumer 为壳、Core 为通用组件源、Other 为独立业务模块三应用各自独立构建部署运行时通过 Module Federation 组合端口 8080/9000/9001 之间的跨源访问由Access-Control-Allow-Origin: *保障。配置层面remotes壳端声明远端地址、exposes远端声明可共享模块、shared声明共享依赖三者缺一不可生产构建后可用http-server托管各dist目录验证静态部署形态下的联邦组合。实践层面若你的团队正从单体 Vue 2 应用向微前端拆分可参照本示例先抽取展示型组件如 Core 的 Button/Section再逐步迁移带业务状态的模块如 Other 的 MainComponent并同步建立类似 commonChecks.spec.ts 的跨端一致性测试作为每次迭代的回归基线。关于本示例的更多运行细节可随时回看仓库根目录的 vue-cli/readme.md 及各子应用内的配置与源码。赞分享示例工程【免费下载链接】module-federation-examplesImplementation examples of module federation , by the creators of module federation项目地址https://gitcode.com/gh_mirrors/mo/module-federation-examples点击查看免费下载相关推荐module-federation-examples 自动 Vendor 共享实战用 AutomaticVendorFederation 免手写的微前端依赖去重module federation examples 自动 Vendor 共享实战用 AutomaticVendorFederation 免手写的微前端依赖去示例工程基于 Vite 的 Module Federation Vue3 微前端host/remote 架构与跨应用状态共享实战解析基于 Vite 的 Module Federation Vue3 微前端host/remote 架构与跨应用状态共享实战解析 本篇文章围绕 module fe示例工程Symfony/Translation与微前端使用Vue 3ViteModule Federation构建多语言应用Symfony/Translation与微前端使用Vue 3ViteModule Federation构建多语言应用 在现代Web开发中微前端架构和国际国际化后端上一篇Clappr 开源仓库开发指南LernaYarn Monorepo 架构、工具链与协作规范全解析下一篇XHS-Downloader 自定义命名与批量下载教程5 个设置让下载文件不再一团乱创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑