# @micro-zoe/micro-app 微前端面试题 > 基于 Vue 3 + Vite 主应用搭建实战经验整理,涵盖从项目初始化、配置、到 bug 排查的全流程。 --- ## 一、基础概念 ### Q1:什么是微前端?micro-app 相比其他方案有什么优势? **答:** 微前端是一种将多个独立的前端应用组合成一个统一应用的架构模式。每个子应用可以独立开发、独立部署、使用不同的技术栈。 `@micro-zoe/micro-app`(京东出品)的核心优势: - **零依赖**:不依赖 single-spa,完全自研 - **类 WebComponent**:使用 `` 标签加载子应用,对开发者透明 - **双沙箱模式**:同时支持 with 沙箱和 iframe 沙箱 - **不限制技术栈**:主应用和子应用可以任意组合(Vue 2/3、React、原生 HTML 等) - **兼容 Vite**:通过 iframe 模式完美支持 Vite 构建的子应用 | 对比维度 | micro-app | qiankun | |----------|-----------|---------| | 接入成本 | 低(类 WebComponent) | 中(需改造子应用入口) | | Vite 支持 | 原生支持(iframe 模式) | 需额外配置 | | 沙箱方案 | with + iframe 双模式 | 基于 Proxy 的沙箱 | | 包体积 | ~300KB | ~100KB | --- ### Q2:micro-app 主应用和子应用之间是如何隔离的? **答:** micro-app 提供**三层隔离**: 1. **样式隔离**(`disable-scopecss`,默认开启): - 为子应用的每个样式规则自动添加 `micro-app[name=xxx]` 前缀,限制样式作用域 2. **JS 沙箱隔离**(`disable-sandbox`,默认开启): - **with 沙箱**:通过 `with(window.proxy)` + `new Function()` 执行子应用 JS,将子应用的全局变量操作代理到隔离的 microWindow 上 - **iframe 沙箱**:将子应用放入 iframe 中运行,利用浏览器原生的 iframe 隔离 3. **元素隔离**(`shadowDOM`,可选): - 将子应用放入 Shadow DOM,彻底隔离 DOM 树 --- ## 二、项目搭建 ### Q3:使用 Vue 3 + Vite 搭建 micro-app 主应用需要哪些步骤? **答:** 核心 4 步: ```ts // 1. 安装依赖 npm install @micro-zoe/micro-app vue-router@4 // 2. vite.config.ts — 将 注册为自定义元素 export default defineConfig({ plugins: [ vue({ template: { compilerOptions: { isCustomElement: (tag) => /^micro-app/.test(tag) } } }) ], server: { port: 8080 } }) // 3. main.ts — 在 Vue 实例化前启动 micro-app import microApp from '@micro-zoe/micro-app' microApp.start({ /* 全局配置 */ }) createApp(App).use(router).mount('#app') // 4. 页面中使用 标签加载子应用 ``` --- ### Q4:为什么要在 `vite.config.ts` 中配置 `isCustomElement`? **答:** `` 是一个**自定义 HTML 标签**,不是 Vue 组件。Vue 模板编译器默认会把所有非标准 HTML 标签当作 Vue 组件去寻找,找不到就会报警告: ``` [Vue warn]: Failed to resolve component: micro-app ``` 通过 `isCustomElement: (tag) => /^micro-app/.test(tag)` 告诉编译器:以 `micro-app` 开头的标签是自定义元素,跳过 Vue 组件解析。 **延伸**:如果子应用中也使用了 ``(嵌套微前端),同样需要配置。 --- ### Q5:主应用路由如何设计才能正确匹配子应用? **答:** 使用 Vue Router 的**通配符** `:page*` 匹配子应用所有内部路由: ```ts const routes = [ { path: '/', redirect: '/home' }, { path: '/home', component: () => import('@/views/Home.vue') }, // 关键::page* 匹配 /child-app 及其下所有子路由 { path: '/child-app/:page*', component: () => import('@/views/ChildApp.vue') } ] ``` **为什么用 `:page*` 而不是 `*`?** - `*` 只在 Vue Router 3 中可用 - Vue Router 4 中必须使用 `:page*`(或 `:pathMatch(.*)*`)来匹配多级路径 - 这样 `/child-app/page1`、`/child-app/a/b/c` 都能被正确捕获 --- ## 三、沙箱机制(重点 Bug 来源) ### Q6:micro-app 的两种沙箱模式有什么区别?如何选择? **答:** | 特性 | with 沙箱 | iframe 沙箱 | |------|-----------|-------------| | 配置 | `iframe: false`(默认) | `iframe: true` | | 原理 | `with(window.proxy)` + `new Function()` | 浏览器原生 iframe | | ES Module | ❌ 不支持 `import`/`export` | ✅ 原生支持 | | 性能 | 较快(无额外渲染) | 略慢(需创建 iframe) | | 隔离性 | 中等(Proxy 代理) | 强(浏览器原生隔离) | | 调试体验 | 较好(同 document) | 较差(跨 iframe) | | 适用场景 | Webpack 构建的 UMD 应用 | **Vite 构建的应用** | **选择原则:** - **Vite 子应用 → 必须 `iframe: true`** - Webpack UMD 子应用 → `iframe: false` 即可 - 对样式/JS 隔离要求极高的场景 → `iframe: true` --- ### Q7:遇到 `Cannot use import statement outside a module` 报错,是什么原因?如何解决? **答:** 这是 micro-app 主应用对接 Vite 子应用时**必踩的坑**。 **报错堆栈:** ``` [micro-app] app vue2-app: { error: SyntaxError: Cannot use import statement outside a module at new Function () } ``` **根因分析:** 1. Vite 开发服务器输出的 JS 是 ` ``` 解决:子应用 Vite 配置 `base` 或使用相对路径 **2. `baseroute` 与 `base` 不匹配:** ```ts // 主应用 // 子应用 vite.config.ts export default defineConfig({ base: '/child-app/' // 必须与 baseroute 一致 }) ``` --- ## 九、实战总结 ### Q20:这套微前端架构在生产环境中部署需要注意什么? **答:** 1. **子应用独立部署**:每个子应用有自己独立的 CI/CD 流水线,版本号独立管理 2. **统一资源路径管理**:通过环境变量管理各子应用的 URL: ```ts export const subApps = [{ name: 'vue2-app', url: import.meta.env.VITE_CHILD_APP_URL || 'http://localhost:5173/', baseroute: '/child-app', }] ``` 3. **Nginx 配置**: - 所有子应用必须配置 CORS 头 - 主应用和子应用建议部署在**同源**下(同协议、同域名、同端口),可避免大量跨域问题 - 如果异构部署,需要配置反向代理统一转发 4. **公共依赖提取**:将 Vue、Vue Router 等公共依赖配置为 external,避免重复加载: ```ts // vite.config.ts build: { rollupOptions: { external: ['vue', 'vue-router'] } } ``` 5. **灰度发布**:利用 `microApp.start()` 的 `plugins.global` 机制,可以在加载子应用 HTML 时做 A/B 测试控制 6. **错误兜底**:配置全局 `error` 回调 + 子应用容器的 `@error` 事件,展示友好的降级页面 --- ## 附录:快速检查清单 | 检查项 | 正确配置 | |--------|----------| | Vite isCustomElement | `(tag) => /^micro-app/.test(tag)` | | Vite 子应用沙箱 | `iframe: true`(必须) | | Webpack 子应用沙箱 | `iframe: false` 即可 | | 子应用跨域 | `Access-Control-Allow-Origin: *` | | 子应用挂载 id | 不能用 `#app`,需独立命名 | | 路由通配符(Vue Router 4) | `:page*`,不是 `*` | | lifeCycles 回调参数 | `(e: CustomEvent, appName: string)` | | 子应用路由 base | `window.__MICRO_APP_BASE_ROUTE__ \|\| '/'` |