微前端的本质不是技术栈隔离,而是团队“协作协议”

我们的前端系统一度拆成了 7 个子应用:A 是核心系统,B 是订单,C 是库存......最开始大家都觉得:"哎,模块化、多团队并行、还能独立部署,好事啊。"

真做下去,才发现微前端的难度根本不是"怎么加载子应用",而是"怎么让子应用之间不互扯后腿"

下面讲一些我们真实踩过的坑,和后来定下的协作协议。


✅ 子应用上线前,必须实现这几个 export 接口

我们要求每个子应用 export 三个固定函数:

ts 复制代码
// 子应用入口
export function mount(container: HTMLElement, props: any): void

export function unmount(container: HTMLElement): void

export function getRoutes(): RouteConfig[]

不然你加载是加载进来了,副作用挂在全局,切换页面残留一堆事件,调试根本找不到源头。


✅ 路由统一注册:子应用不能自己定义路由表

我们把子应用暴露的路由集中注册到主应用的路由体系中:

子应用路由(伪代码):

ts 复制代码
export const MODULE_NAME = 'sub-app-a'

export function getRoutes(): RouteRecordRaw[] {
  return [
    {
      path: '/home',
      name: 'SubAHome',
      component: () => import('./pages/Home.vue'),
      meta: {
        title: '子应用A首页',
        permission: 'suba.home.view'
      }
    },
    {
      path: '/list',
      name: 'SubAList',
      component: () => import('./pages/List.vue'),
      meta: {
        title: '子应用A列表',
        permission: 'suba.list.view'
      }
    }
  ]
}
ts 复制代码
import { getRoutes as getSubARoutes } from 'sub-app-a'

const appRoutes = [
  ...getSubARoutes().map(route => ({
    ...route,
    path: `/a${route.path}`,
    meta: { ...route.meta, from: 'sub-a' }
  }))
]

router.addRoutes(appRoutes)

为什么这么做?因为我们要控制:

  • 子路由路径前缀,防止冲突;
  • meta 字段统一格式,用于权限、埋点、导航。

✅ 权限协议:每个页面必须附带权限标识码

我们统一约定了权限字段 meta.permission

ts 复制代码
{
  path: '/order/detail',
  name: 'OrderDetail',
  component: OrderDetailPage,
  meta: {
    permission: 'order.view.detail',
    title: '订单详情',
    icon: 'icon-detail'
  }
}

权限验证逻辑只在主应用执行,子应用无需关注,只需要写清楚"你这个页面需要什么权限"即可。


✅ 埋点上报:不许各写各的

有人喜欢用神策,有人喜欢自己写埋点代码,我们统一规定:

ts 复制代码
window.__tracker__.track('page_view', {
  app: 'sub-a',
  page: 'OrderDetail',
  userId: props.user.id
})

不允许用 console.log 来"假装"打点,不允许乱传字段。tracker SDK 封装字段统一结构,主应用注入,每个子应用只管调用。


✅ 样式隔离:必须使用命名空间 + 注入 token

子应用不允许写 * { margin: 0 } 这种 reset 样式,统一规范:

  • BEM 命名:.sub-a-button.sub-a-card
  • 所有颜色、字体等样式通过 props.themeToken 注入
ts 复制代码
export function mount(container: HTMLElement, props) {
  document.documentElement.style.setProperty('--primary-color', props.themeToken.primaryColor)
  createApp(App).mount(container)
}

不接受"我们这个子系统不在乎样式统一"这种话,谁进系统谁配合。


✅ 依赖约定:大依赖统一 CDN external,不许重复打包

比如 element-plus、echarts、dayjs 这些,全部从主应用加载,子应用配置:

ts 复制代码
externals: {
  vue: 'Vue',
  'element-plus': 'ElementPlus',
  echarts: 'echarts'
}

不然每个子应用都打进一份,用户下载多倍资源,性能炸裂。


✅ 子应用部署:统一支持 manifest.json 文件注册信息

每个子应用部署完自动生成一份 manifest.json

json 复制代码
{
  "name": "sub-app-a",
  "version": "1.2.5",
  "entry": "https://cdn.xxx.com/sub-a/main.js",
  "routes": ["/a/home", "/a/detail"],
  "team": "order"
}

主应用根据 manifest 来决定是否拉取新版子应用资源,实现灰度、热更新、版本回退等逻辑。


🚫 我们曾踩过的几个坑(避免再犯)

  • 坑一:多个子应用各自搞 Vuex、React-Redux,状态无法共享,也无法追踪 bug。 → 解决:统一 useGlobalModel hook 管理共享状态。
  • 坑二:样式污染,某个子应用加了 global.css 把主系统 nav 样式覆盖了。 → 强制 scoped + 命名空间。
  • 坑三:用户登录状态各自读取 cookie,结果 session 脱节。 → 所有接口请求必须用主应用封装的 fetch。

你可以不搞微前端,用 monorepo、模块化都能解决开发分工。但只要你一旦拆出子仓库,团队就必须有协议

这个协议不是靠写在 wiki 里解决的,而是靠 CI 校验、接口检查、主应用调度逻辑来"落地"的。

所以我们对"微前端"这四个字的理解是:技术选型其次,协作规范优先;模块拆分其次,系统统一优先。

📌 你可以继续看我的系列文章

相关推荐
&白帝&4 分钟前
CSS Background 相关属性详解 文字镂空效果
前端·css
我的心巴14 分钟前
Vue2 ElementUI Tree 拖动目标节点能否被放置及获取放置位置
前端·vue.js·elementui
ze_juejin26 分钟前
Subject、BehaviorSubject、ReplaySubject、AsyncSubject、VoidSubject比较
前端·angular.js
每天吃饭的羊30 分钟前
面试-TypeScript 场景类面试题
前端
CRMEB定制开发43 分钟前
CRMEB 注释规范:多端适配下的代码可读性提升之道
前端
中雨202544 分钟前
HarmonyOS Next快速入门:TextInput组件
前端
白晓明1 小时前
HarmonyOS NEXT端云一体化云侧云函数介绍和开发
前端·harmonyos
白晓明1 小时前
HarmonyOS NEXT端侧工程调用云函数能力实现业务功能
前端·harmonyos
锋利的绵羊1 小时前
【小程序】迁移非主包组件以减少主包体积
前端·微信小程序·uni-app