vue-vben-admin 接入 qiankun 微前端:3 个关键机制决定落地成败
【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. It's fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin
vue-vben-admin 是基于 Vue3 + Vite + TypeScript 的 Monorepo 中后台模板,其apps/目录下并列着 web-antd、web-ele 等 5 个可独立运行的应用。本文围绕一个真实场景展开:把旧版 Ant Design 页面和新版 Element 页面装进同一个壳应用,讲清 qiankun 微前端在 vben 工程里的接入路径、两个最容易踩坑的机制(生命周期调度与沙箱样式隔离),以及什么情况下其实不该上微前端。
场景:旧 AntD 页面和新 Element 页面共用一个壳
假设公司现状是:核心业务跑在 Ant Design Vue 上,新模块团队选了 Element Plus,两边都不愿意重写成对方的技术栈。vue-vben-admin 的 Monorepo 结构天然适合这个局面——apps/web-antd和apps/web-ele本来就各自是一个完整壳应用,共享packages/下的布局、权限、请求等能力。要做的就是选其中一个当主应用(壳),另一个通过 qiankun 注册为微应用,按路由前缀激活。
🧩 需要注意的是:vben 仓库本身并没有内置 qiankun,以下所有改造都是基于现有工程结构的增量接入,不需要动packages/里的共享层。
接入方式选型:直接用 HTML 入口,别折腾 UMD 构建
qiankun 支持 HTML 入口和 JS(UMD)入口两种加载方式。我的建议很明确:开发和生产都用 HTML 入口,entry直接指向微应用的部署地址即可,微应用保持现有的 Vite 构建产物形态不变:
import { registerMicroApps, start } from 'qiankun'; registerMicroApps([ { name: 'web-ele', entry: 'http://localhost:5555', container: '#subapp-container', activeRule: '/subapp/ele', props: { token: accessStore.accessToken }, }, ]); start({ sandbox: { experimentalStyleIsolation: true } });UMD 入口要求重写微应用的构建链路(library 模式、externals、全局变量命名),收益却只有"少解析一个 HTML",对 vben 这种带 i18n、动态路由的应用来说,重写成本远高于收益。唯一必须做的是让微应用的 Vite 开发服务器返回 CORS 头,否则主应用拉取入口 HTML 会被浏览器拦截:
// apps/web-ele/vite.config.ts vite: { server: { headers: { 'Access-Control-Allow-Origin': '*' }, }, },生命周期改造:vben 的 bootstrap 链只有一个挂载点,但也只有一处要改
🔍 这是接入里最舒服的部分。vben 每个应用的入口apps/web-ele/src/main.ts只做两件事:initPreferences初始化偏好,然后import('./bootstrap')执行全部挂载逻辑——i18n、Pinia、组件适配器、路由守卫,最终createApp(App)并app.mount('#app')。也就是说整个应用的生命周期收敛在bootstrap.ts一个函数里,把它包成 qiankun 的 mount/unmount 即可:
// apps/web-ele/src/main.ts(简化) let app: App | null = null; export async function mount(props: any = {}) { const { container, token } = props; if (token) useAccessStore().$patch({ accessToken: token }); const { bootstrap } = await import('./bootstrap'); app = await bootstrap(namespace, container); // 需小改 bootstrap } export async function unmount() { app?.unmount(); app = null; } if (!window.__POWERED_BY_QIANKUN__) { initApplication(); // 独立运行时行为不变 }配套改两处细节:一是bootstrap.ts目前不返回 app 实例,加一个return app才能支持卸载;二是它内部写死了mount('#app'),改成container?.querySelector('#app') || '#app'以兼容壳应用注入的容器。
这里藏着一个权限相关的坑:vben 的路由守卫(apps/web-ele/src/router/guard.ts)在拿不到accessToken时会强制跳登录页。微应用模式下列表页第一次渲染时如果 token 还没从 props 写入 store,用户会被瞬间甩到登录页再弹回来。所以 mount 里的 token 注入必须发生在路由初始化之前,别放在onMounted之类的回调里。
qiankun 沙箱模式下样式冲突的两种解法
两个应用各自引入了组件库的全局样式和 Tailwind 产物,混在同一份 document 里必然冲突:AntD 的.ant-*和 Element 的.el-*类名不撞,但 reset 样式、Tailwind preflight、CSS 变量会互相覆盖。qiankun 沙箱给两条路:
方案一:strictStyleIsolation(Shadow DOM 封装)。隔离最彻底,但对 vben 不适用——它的 Modal、抽屉、tippy 提示都是 portal 到document.body的,Shadow DOM 会把它们全部"吃掉",表现为弹窗不显示或飞出去。
方案二:experimentalStyleIsolation(自动加属性选择器前缀)+ 主题变量收敛。这是我在 vben 场景下的推荐解法:开启前缀隔离解决基础样式串扰,同时利用 vben 的 preferences 体系让两个应用共享同一套设计变量(两个应用都走packages/@core/preferences初始化),弹窗类 portal 组件不受影响。代价是前缀会给选择器加长度、且对运行时动态插入的样式不生效,需要配合组件库的样式懒加载策略规避。
落地时真正踩到的三个坑 ⚠️
路由 base 与 activeRule 不一致。微应用内部的 vue-router 默认 base 是/,而它在壳里挂在/subapp/ele下,子路由点击后地址栏变化会脱离激活前缀,页面白屏。解法是把微应用的 router base 显式配置为 activeRule 路径,两边严格一致。
双份 Vue 运行时。主应用和微应用各自打包一份 Vue,同一页面存在两个 reactivity 系统,内存和性能都有实打实的开销(在含 20+ 路由的管理台页面下,可观测到明显多出的运行时体积)。缓解方式是用 pnpm workspace 的 catalog 机制(见pnpm-workspace.yaml)把主、微应用的 Vue 版本钉死一致,至少保证行为不分裂。
调试链路变长。微应用报错发生在 qiankun 的 proxy sandbox 里,错误堆栈指向的是包装后的代码位置,直接打断点很痛苦。实用做法是保留window.__POWERED_BY_QIANKUN__判断,本地单独起微应用复现,配合主应用侧的错误监控面板兜底。
适用边界:先回答"是否真的需要微前端"
给出我的判断标准。如果你的所有团队都愿意接受 vben 的 Monorepo 协作方式,那其实不需要 qiankun:apps/下多开一个应用、packages/里沉淀共享业务,独立部署的能力已经由 pnpm workspace + Turborepo 提供,团队各改各的 app 目录即可。Micro-frontend 的价值在于"独立部署 + 异构技术栈 + 存量系统无法重写"三者至少占两条——只有换组件库不算,那用 vben 的多 app 结构就够;老系统跑的是 React、Vue2 或原生模板,且发布节奏被主干阻塞,才值得引入 qiankun 这套运行时开销。
落到本文场景:旧 AntD 页面是存量重写不了的,新 Element 模块需要独立迭代节奏,两条线都成立,接入是划算的。改动的范围也很收敛——main.ts加生命周期导出、bootstrap.ts返回实例、vite 加 CORS 头、沙箱开实验性样式隔离,共享层一行不动。微前端不是架构升级,是把"拆分"这个组织决策翻译成了工程结构,想清楚这一点再动手。
【免费下载链接】vue-vben-adminA modern vue admin panel built with Vue3, Shadcn UI, Vite, TypeScript, and Monorepo. It's fast!项目地址: https://gitcode.com/GitHub_Trending/vu/vue-vben-admin
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考