微前端架构已成为构建可扩展、模块化应用程序的流行方法。它将整体前端拆分成更小、独立的微前端 (MFEs),从而实现团队独立开发、单独部署和提升可维护性。本文将探讨一个基于 Vue 3、Vite 和 Module Federation 的微前端示例,并利用动态路由管理构建灵活、可扩展的架构。
在每个微前端都需要自身 Vue 实例的情况下,这种方法尤为有效,允许团队在避免依赖冲突的情况下开发和维护独立的前端服务。此外,该架构仅加载必要的 Vue 实例,确保性能良好,同时保持微前端间的隔离。我们使用 Module Federation 运行时和路由清单在运行时动态获取和加载 MFEs。这意味着 MFEs 不会打包到主应用程序中,而是在需要时按需加载,从而提升灵活性并减少初始加载时间。
微前端架构概述 以下是我们微前端设置的工作原理概述:
+----------------+ +------------------+ +------------------+ | 主应用 | | 微前端 1 | | 微前端 2 | | (Vue Router) | | (app-1) | | (app-2) | | loader.vue | | Vue 实例 | | Vue 实例 | +----------------+ +------------------+ +------------------+
- 主应用 处理路由并在运行时动态加载 MFEs。
- loader.vue 负责根据路由变化安装和卸载微前端。
- 每个微前端 拥有自己的 Vue 实例独立运行,并通过 Module Federation 公开组件。
快速上手 克隆仓库并安装依赖:
git clone https://github.com/lmlong-huynh/micro-frontend-sample.git cd micro-frontend-sample npm install
启动所有微前端和主应用:
npm run dev
或者单独启动每个微前端:
cd packages/host && npm run dev cd packages/app-1 && npm run dev cd packages/app-2 && npm run dev
路由清单配置 路由清单在主应用中动态注册微前端路由。所有路由都指向 loader.vue,而不是直接引用远程应用。清单中,我们定义两个属性:一个指定路由对象,另一个指示哪个 MFE 以及从哪里加载。
// routeManifest.js export const routeManifest = [ { route: { path: '/app-1', name: 'app1', meta: { requiresAuth: false }, }, remote: { module: 'app1/app' } }, { route: { path: '/app-2', name: 'app2', meta: { requiresAuth: false }, }, remote: { module: 'app2/app' } } ];
在路由器文件中,我们使用清单创建所有路由。这是因为导航到页面时,我们需要知道要加载哪个远程 MFE 并进行渲染。
所有 MFE 路由都指向 loader.vue,因为这里包含了处理 MFE 安装和卸载的大部分逻辑。它也确保每个 MFE 只有一个 Vue 实例(总共两个实例,包括主应用)。
// router/index.js import { createRouter, createWebHistory } from 'vue-router'; import routeManifest from '../routeManifest'; const getRoutes = () => { return routeManifest.map((mfe) => ({ path: mfe.route.path, name: mfe.route.name, meta: mfe.route.meta, component: () => import('@/components/loader.vue'), // 所有路由都指向 loader.vue })); }; const routes = getRoutes(); const router = createRouter({ history: createWebHistory(), routes, }); export default router;
加载器组件 所有路由都指向 loader.vue,而不是直接渲染微前端。当访问路由时,该组件会动态加载并安装微前端,并在运行时使用 Module Federation 从远程主机获取 MFE。
在 loader.vue 中,我们跟踪当前路由。通过了解路由,我们可以确定要加载哪个远程 MFE。此外,我们跟踪当前已安装的 MFE,以便在加载新的 MFE 之前可以卸载它。此方法确保没有不必要的 Vue 实例正在运行。
<template> <div ref="containerRef"></div> </template> <script> import { ref, onMounted, watch } from 'vue'; import { useRoute } from 'vue-router'; import { useModuleFederation } from '@/plugins/federationPlugin'; import routeManifest from '../routeManifest'; export default { setup() { const route = useRoute(); const moduleFederation = useModuleFederation(); const containerRef = ref(null); const currentModule = ref(null); // ... (其余代码与原文相同) } }; </script>
结论 本文提供了一个简单的解决方案。当然,还有其他用例,例如从主应用处理 MFE 中的嵌套子路径,我们可以在后续文章中探讨。