Vue微前端中多vue-router实例如何实现路由作用域隔离
Vite+Module Federation下Vue多router实例隔离方案
问题核心原因
- 共享依赖配置缺失:仅共享了
vue,未统一共享vue-router且未开启单例模式,容易出现多实例上下文冲突。 - 路由上下文污染:直接暴露子应用单个视图组件时,组件上层只有宿主应用注入的router实例,子应用内部的
<router-link>、useRouter()调用默认会沿组件树向上找到最近的注入值(即宿主router),所有跳转自然全走宿主逻辑。 - 路由规则不匹配:宿主路由只配置了
/login单条规则,子应用跳转内部子路径时宿主路由无匹配规则直接拦截,子应用router根本没机会响应路径变化。 - base路径不对齐:子应用router配置的base是
/login,但宿主路由的全局base是/app/,实际子应用挂载路径为/app/login,路径前缀不匹配导致子应用路由无法正确解析URL。
分步配置方案
1. 修正两端Module Federation共享配置
保证vue、vue-router全局单例,避免多实例版本冲突,同时子应用不要直接暴露单个视图组件,要暴露带完整路由上下文的入口。
子应用federation配置:
federation({ name: 'login-mf', filename: 'loginEntry.js', exposes: { './LoginMF': './src/bootstrap.js', // 替换成带路由的根入口 }, shared: { vue: { singleton: true, requiredVersion: '^3.3.0' }, // 版本号和自身依赖对齐 'vue-router': { singleton: true, requiredVersion: '^4.2.0' } } })
宿主应用federation配置shared段同步修改:
shared: { vue: { singleton: true, requiredVersion: '^3.3.0' }, 'vue-router': { singleton: true, requiredVersion: '^4.2.0' } }
2. 子应用封装独立路由根入口
新建src/bootstrap.js作为子应用暴露入口,在根组件内部独立注入自身router实例,利用Vue的provide层级特性实现路由作用域隔离:
import { h, provide } from 'vue' import { createRouter, createWebHistory } from 'vue-router' import LoginRoot from './views/Login.vue' import LoginForm from './views/LoginForm.vue' import TestView from './views/Test.vue' // 子应用内部路由 const routes = [ { path: '/', redirect: "/form" }, { path: "/form", name: "LoginForm", component: LoginForm }, { path: '/test/:id', name: "TestView", component: TestView }, ] const childRouter = createRouter({ // base对齐宿主分配的完整前缀:宿主base是/app/,子应用挂载在/login下,集成时全路径为/app/login history: createWebHistory(import.meta.env.DEV ? '/login' : '/app/login'), routes, }) export default { name: 'LoginMFRoot', setup() { // 向当前子应用组件树注入自身router实例,优先级高于上层宿主注入的router provide('router', childRouter) provide('route', childRouter.currentRoute) return () => h(LoginRoot) }, install(app) { app.use(childRouter) } }
3. 修正子应用内部跳转写法
之前的<router-link>传参错误,字符串形式会被解析为路径,命名路由需要用对象写法:
<template> <p>Login view</p> <router-link :to="{ name: 'LoginForm' }">Login</router-link> <router-link :to="{ name: 'TestView', params: { id: 1 } }">TestView</router-link> <router-view></router-view> </template>
4. 调整宿主路由匹配规则
给子应用路由加通配符,匹配/login下的所有子路径,避免宿主路由提前拦截子应用内部导航:
const LoginMF = () => import("login-mf/LoginMF") const routes = [ { path: "/", component: HelloWorld }, // 通配符匹配所有子路径,统一交给子应用根组件处理 { path: '/login/:pathMatch(.*)*', component: LoginMF }, ] const router = createRouter({ history: createWebHistory('/app/'), })
效果说明
配置完成后两个router实例完全隔离:
- 子应用内部所有导航调用只会命中自身注入的router实例,不会污染宿主路由状态
- URL会按照
/app/login/xxx的格式更新,宿主路由只匹配前缀段,后续路径由子应用路由自行解析 - 子应用独立开发时base自动切换为
/login,不影响单独调试
内容的提问来源于stack exchange,提问作者Ismael Ordás
相关产品推荐
相关产品推荐

