如何在子应用回滚时保持基座无需重启

解读

在微前端架构里,基座(主应用)负责统一路由、权限、公共资源,而子应用独立构建、独立部署。当线上子应用出现缺陷需要“秒级回滚”时,若每次回滚都要求重启基座,会导致所有子应用短暂不可用,违背“故障隔离、增量发布”的设计初衷。
国内主流方案(qiankun、micro-app、无界)都基于运行时加载而非“编译期打包”,因此回滚的关键是让基座在运行态拿到旧版本子应用,而不重启自身进程
面试官想考察:

  1. 是否理解微前端“生命周期钩子 + 运行时加载”的本质;
  2. 是否能在 Grunt 构建层把“版本化、差异化、可回滚”做进流水线;
  3. 是否熟悉国内云原生发布习惯(蓝绿、金丝雀、OSS + CDN 秒级切换)。

知识点

  1. 子应用版本化构建
    Gruntfile 中通过 grunt-contrib-uglifygrunt-filerevgrunt-usemin 把子应用打出带 hash 的入口 bundle(如 app.2c3e4f5a.js),并同步生成 manifest.json 记录版本映射。
  2. 非覆盖式发布
    将产物按“版本文件夹”上传 OSS:/app-a/1.0.11//app-a/1.0.10/;CDN 路径永不覆盖旧文件,实现“秒级回滚只需切路径”。
  3. 运行时路由与钩子
    基座在 registerMicroApps 时读取远端配置中心(Nacos、Apollo、自建配置服务)拿到 entry 字段,如 //cdn.xxx.com/app-a/1.0.10/index.js;回滚即改配置,基座下次加载子应用自动取旧入口,已挂载的子应用保持不动
  4. 沙箱清理与内存泄漏防控
    回滚前主动调用 unmount 生命周期,清除 window 污染、事件监听、定时器;qiankun 的 proxySandbox 在卸载时自动重置全局变量,防止旧代码残留。
  5. 灰度与优雅降级
    配置中心支持用户维度灰度:cookie 里带 app-a-version=1.0.10 的优先回滚,其余用户仍走 1.0.11;基座侧通过 fetch 兜底策略,若新入口 5s 未响应自动降级到上一稳定版本。
  6. Grunt 自动化回滚流水线
    新增 grunt-task-rollback
    • 调用 OSS API 把 /app-a/1.0.10/x-oss-object-acl 设为 public-read
    • 调用配置中心 OpenAPI 把 app-a.entry 字段改为 1.0.10 的 CDN 地址;
    • 通过 grunt-webhooks 触发钉钉/飞书机器人通知。
      全程无需重新构建、无需重启基座,平均耗时 3~5 秒。

答案

  1. 构建阶段:Gruntfile 把子应用打出带 hash 的入口文件,并按版本号上传到 OSS 非覆盖式目录。
  2. 发布阶段:基座通过配置中心动态获取子应用 entry,而不是写死路径;首次加载时把入口脚本缓存在IndexedDB + LRU,减少二次网络请求。
  3. 回滚阶段
    a. 运维在 Grunt 流水线执行 grunt rollback:app-a:1.0.10
    b. 任务脚本把配置中心对应 entry 字段改为 1.0.10 的 CDN 地址;
    c. 基座监听 popstate 或路由切换时,发现子应用需要重新加载,则拉取旧版本入口;当前已挂载的子应用实例保持运行,直到下一次路由切换才卸载,实现“热回滚、零重启”。
  4. 兜底策略:若新入口加载失败,基座自动降级到上一版本;同时上报 Sentry,Grunt 侧定时任务 5 分钟内禁止再次发布该子应用,防止“滚挂”。

拓展思考

  1. 多子应用并行回滚:当一次发布涉及 app-a、app-b 两个子应用,如何在一次 Grunt 任务里做“事务级回滚”?
    思路:配置中心支持批量事务接口,Grunt 任务先把两个子应用的 entry 统一写入一个 rollbackTicket,成功后再原子提交;若任一失败则整体回滚,保证一致性
  2. 子应用样式污染:旧版本 CSS 也可能有缺陷,回滚时如何确保样式也同步还原?
    方案:CSS 同样按版本文件夹存放,并在子应用 mount 时动态插入 <link>,卸载时移除;借助 ShadowDOM + CSS Modules 可彻底隔离,但需权衡浏览器兼容性。
  3. 本地开发如何模拟回滚
    在 Grunt 里起两个 dev-server,端口 7100(v1.0.11)、7101(v1.0.10),通过 grunt-contrib-proxy 把基座请求转发到不同端口,前端开发者无需重启基座即可一键切换版本,提前验证回滚逻辑。