假设你管理着一家传统工厂。所有产品在同一条流水线上生产:拧一颗螺丝要停整条线,招一个新人要读几万行图纸,改一处设计要重新调试整条生产链。后来你把工厂改造成了一座大型商场:每个品牌租下自己的店铺,独立装修、独立营业、独立翻新;商场只提供门厅、水电、安保和公共导引。这座“会自我生长的商场”,就是微前端架构(Micro Frontend)在现实世界里的投影。 在 Web 前端世界,传统工厂叫“巨石应用”(Monolith):一个代码仓库打包出整个产品,一个团队改动可能影响所有用户。微前端把应用拆分成多个可独立开发、独立部署、独立运行的小应用,再由一个基座把它们在浏览器里组合起来。你在导航栏点哪个区域,哪个子应用就“开店营业”。更妙的是,qiankun 会为每个子应用装上“隔音墙”(沙箱隔离),而 Module Federation 能给所有子应用建一座“中央厨房”(依赖共享)。这篇文章就用商场的语言,带你把这套架构从概念走到实践。

岗位关联

对前端开发者而言,微前端是处理大型业务系统“拆与合”的必修课,也是从“会写页面”走向“能设计前端架构”的分水岭。

目录
  1. 可视化演示
  2. 概念与价值
  3. 核心机制
  4. 乾坤沙箱
  5. 模块联邦
  6. 工程策略
  7. 实践挑战
  8. AI 应用场景
  9. Python 演示
  10. 常见误区
  11. 面试题

可视化演示

演示主应用(Shell)编排多个独立微应用,Module Federation共享远程模块,qiankun沙箱隔离与按需加载的架构机制。

本节配有交互动效(进入视口后自动加载,约 3KB)。

微前端架构 Shell Orch 编排独立微应用

概念与价值

传统公司像一间巨型工厂:所有业务模块挤在同一条生产线上,一个按钮的改动可能让全厂停产。老板决定把工厂改造成购物中心——每个品牌独立开店、独立装修、独立招聘,商场只做公共物业。这正是微前端架构的隐喻:把庞大的前端工程拆成多个“店铺”,各自为政,又共用同一套基础设施。

放到前端世界,这座“工厂”就是巨石单页应用(Monolith SPA)。几十个团队维护同一个仓库,构建一次要等一根烟的功夫,发一次版要全体陪跑。微前端的定义很朴素:将前端应用拆分成可独立开发、独立部署、独立运行的子应用,再由一个基座在运行时把它们组合成一个完整产品。每个子应用有自己的代码仓库、开发流程和发布节奏,就像每家店有自己的进货渠道和营业时间。

独立部署是微前端最诱人的收益:店铺 A 翻新(发布新版本)时,店铺 B 照常营业,顾客无需离场。同时,技术栈无关让 React、Vue、Angular 甚至老 jQuery 项目都能共存——商场从不规定商家必须卖同一种奶茶。从加载成本上看,这个拆分逻辑更加直观:

回到商场比喻:顾客逛商场只需要经过门厅和目标店铺,其他店铺不必“主动站到脚边”。微前端真正的省,就是按需营业。

Cmono=∑i=1nCi,Cmicro=Cbase+Cactive\displaystyle C_{\text{mono}} = \sum_{i=1}^{n} C_i, \qquad C_{\text{micro}} = C_{\text{base}} + C_{\text{active}}
  1. 认识全量成本等号左边表示巨石应用的加载成本,也就是把所有模块一次性下发给浏览器。
    Cmono\displaystyle C_{\text{mono}}
  2. 单体求和右侧的求和符号把 n 个模块的体积全部加起来,没有一个模块能偷懒。
    ∑i=1nCi\displaystyle \sum_{i=1}^{n} C_i
  3. 微前端拆分等号右边第一项是基座外壳的体积,第二项是当前被激活的子应用体积。
    Cbase+Cactive\displaystyle C_{\text{base}} + C_{\text{active}}
  4. 对比省下的部分用户同一时刻只走一条业务主线,其余子应用可以按需加载,所以微前端成本远小于全量打包。
    Cmicro<Cmono\displaystyle C_{\text{micro}} < C_{\text{mono}}

核心机制

商场的招商部不卖货,只负责把店铺引进来、安排好位置、定好开门关门的规矩。微前端里的“基座应用”(主应用)就是招商部:它承载导航栏、登录态、公共区域和路由分发,而具体业务全交给子应用。没有招商部的统一调度,店铺再多也只会是一盘散沙。

基座的核心工作是“注册与路由”:每个子应用像商家签入驻合同一样,把自己的名称、入口文件、渲染节点登记到基座;当 URL 变化时,基座根据路由表决定激活哪个子应用。这个“开店流程”被抽象成一套标准的生命周期,qiankun 和 Single-SPA 都遵循它。子应用必须导出生命周期函数,基座负责在正确时机调用它们:

招商部只要把“开关门规矩”定好,任何技术栈的商家都能进场。这就是微前端框架的巧妙之处:用统一的流程,容纳百变的店铺。

A→registerR→loadL→mountM→unmountU\displaystyle A \xrightarrow{\text{register}} R \xrightarrow{\text{load}} L \xrightarrow{\text{mount}} M \xrightarrow{\text{unmount}} U
  1. 注册登记子应用把自己的名字和入口登记到基座,相当于商家与商场签入驻合同。
    A→registerR\displaystyle A \xrightarrow{\text{register}} R
  2. 加载资源基座通过动态 import 拉取子应用的 JS/CSS,相当于商家把货搬进店铺。
    R→loadL\displaystyle R \xrightarrow{\text{load}} L
  3. 挂载上架子应用执行 mount 生命周期,把页面渲染到指定 DOM 节点,相当于开门营业。
    L→mountM\displaystyle L \xrightarrow{\text{mount}} M
  4. 卸载清场路由切走时执行 unmount,清理事件、样式和全局副作用,相当于打烊撤场。
    M→unmountU\displaystyle M \xrightarrow{\text{unmount}} U
  5. 状态轮转整个链路是一个严格状态机,任一步失败都会走降级逻辑,不让商场整体瘫痪。
    A→R→L→M→U\displaystyle A \to R \to L \to M \to U

乾坤沙箱

商场最怕 A 店霓虹灯闪瞎 B 店顾客的眼睛,B 店装修的灰尘飘进 C 店橱窗。qiankun 的沙箱就是每家店专属的“玻璃隔断 + 无尘施工规范”,它解决两类污染:JS 全局污染和样式污染。

qiankun 的 JS 沙箱有两种主流实现。第一种叫快照沙箱:子应用激活前,把 window 上的全局状态“拍照”存起来;卸载时再把 window 恢复成照片里的样子,所有改动被一键抹除。第二种叫 Proxy 沙箱:用浏览器原生 Proxy 拦截对 window 的读写,只记录“被改动过的属性”,恢复成本更低,还能同时运行多个沙箱实例——相当于同时在走廊里给两家店施工而不互相干扰。

样式隔离同样重要。子应用动态插入的 style 标签,在卸载时会被 qiankun 自动移除,避免上一家的“装修气味”飘到下一家。此外,qiankun 支持预加载:用户还在逛当前店铺时,物业已经让下一家店提前备好货(按路由预取资源)。沙箱的核心逻辑可以用快照公式概括:

有了沙箱这堵隔断墙,上一家店的“施工噪音”永远不会影响下一家店的营业体验。

onActivate:  S=Wglobal,onDeactivate:  Wglobal=S\displaystyle \text{onActivate}: \; S = W_{\text{global}}, \qquad \text{onDeactivate}: \; W_{\text{global}} = S
  1. 激活拍照子应用挂载前,把 window 上的全局状态复制一份存到快照变量中。
    S=Wglobal\displaystyle S = W_{\text{global}}
  2. 随意装修子应用运行期间可以自由增删全局变量,就像店内在随意施工。
    ΔW=Wrun−Wglobal\displaystyle \Delta W = W_{\text{run}} - W_{\text{global}}
  3. 卸载还原子应用卸载时把 window 覆盖回快照,所有改动瞬间归零。
    Wglobal=S\displaystyle W_{\text{global}} = S

模块联邦

商场运营几个月后,物业发现每家奶茶店都各自买了制冰机——又贵又占地方。于是商场建了一座“中央厨房”:设备统一采购、统一供应,谁用谁取。Module Federation(MF)就是 Webpack 5 为前端建的中央厨房。

MF 的核心概念有三个:remote(远程店铺)、host(本地店铺)和 shared(共享货架)。远程模块允许子应用 B 把某个组件暴露出去,子应用 A 在运行时通过网络请求直接拉取并渲染,就像 B 店把爆款甜品送到 A 店代售。共享依赖则解决“重复打包”:React、Vue 这类基础库只需加载一次,多家店铺共用一个版本的“设备”。

但是,中央厨房有个棘手问题:A 店想用 React 17,B 店想用 React 18,到底听谁的?MF 的版本协商机制会在运行时检查各应用声明的依赖版本范围,选择一个所有应用都能接受的版本;如果实在找不到,就退化为各自加载各自的副本。版本选择可以抽象成这样一个优化问题:

中央厨房让所有店铺共用一台制冰机,但前提是每家店都接受同一品牌同一型号——这就是版本协商的智慧。

v∗=arg⁡max⁡v∈V{v∣∀i:v∈[vimin⁡,vimax⁡]}\displaystyle v^{*} = \arg\max_{v \in V} \{ v \mid \forall i: v \in [v_{i}^{\min}, v_{i}^{\max}] \}
  1. 收集候选版本V 是所有子应用声明依赖版本的并集,类似汇总各商家想要的制冰机型号。
    V=⋃i=1nVi\displaystyle V = \bigcup_{i=1}^{n} V_i
  2. 逐一验证兼容对每个候选版本 v,检查它是否落在所有应用声明的版本区间内。
    ∀i:  v∈[vimin⁡,vimax⁡]\displaystyle \forall i: \; v \in [v_{i}^{\min}, v_{i}^{\max}]
  3. 取最大值在兼容的候选中选版本最高的,保证功能最新且大家都接受。
    v∗=arg⁡max⁡v{v∣兼容}\displaystyle v^{*} = \arg\max_{v} \{ v \mid \text{兼容} \}
  4. 兜底结果若没有版本兼容,则各自加载自己的依赖,虽然会重复但不会崩溃。
    v∗=∅⇒重复加载\displaystyle v^{*} = \varnothing \Rightarrow \text{重复加载}

工程策略

商场管理不是装修完就万事大吉。物业要出装修手册(样式约束)、装全场广播(状态通知)、做人流调度(性能优化)、准备应急电源(降级容灾)。微前端的工程治理,恰恰是这几件事。

样式防冲突是第一道红线。实践中常用 CSS Modules、CSS-in-JS、手动前缀(如 .shop-a-)来隔离,qiankun 还会在子应用卸载时自动移除动态 style 标签。状态管理则讲究“能不分家就不分家”:优先用 props 传递,辅以全局事件总线或轻量 store,避免把子应用内部状态全塞进全局对象。

性能优化的核心是按需加载 + 预加载 + 依赖共享。用户点开导航的瞬间,系统若能提前把下一个子应用拉取完毕,感知等待时间就会被压缩。假设基座已经稳定加载,预加载的收益可以用下面的式子表示:

最后是降级容灾:子应用加载失败时展示兜底页、自动重试或手动切换,保证一家店停电,整座商场依然灯火通明。工程治理的终极目标,是让顾客察觉不到店铺切换,只看到顺畅的开店与关店。

ΔT=T子应用−T预加载,T感知=T基座+max⁡(0,ΔT)\displaystyle \Delta T = T_{\text{子应用}} - T_{\text{预加载}}, \qquad T_{\text{感知}} = T_{\text{基座}} + \max(0, \Delta T)
  1. 定义子应用耗时T_子应用 是某个子应用从开始加载到渲染完成所需的全部时间。
    T子应用\displaystyle T_{\text{子应用}}
  2. 定义预加载时间T_预加载 是用户还在当前页面时,系统提前拉取下一子应用花费的时间。
    T预加载\displaystyle T_{\text{预加载}}
  3. 求差值若预加载在用户点击前已完成,用户等待时间就是两者差值甚至为零。
    ΔT=T子应用−T预加载\displaystyle \Delta T = T_{\text{子应用}} - T_{\text{预加载}}
  4. 取正保护外层 max 保证即使预加载没完成,也只是退化为原来的加载时间,不会产生负等待。
    T感知=T基座+max⁡(0,ΔT)\displaystyle T_{\text{感知}} = T_{\text{基座}} + \max(0, \Delta T)

实践挑战

开业只是起点。新餐厅要试营业(灰度发布)、保安要巡逻(监控告警)、各商家要做联合活动(团队协作)、商场要定期翻新(生态演进)。微前端的长期运营,也离不开这四件事。

灰度发布是最重要的风险控制手段:新版本先让一小部分用户“试营业”,观察指标没问题再逐步放量。假设新子应用的故障概率是 p,灰度比例是 g,故障影响面 R 会从全量的 p 压缩为:

监控告警方面,要采集子应用加载耗时、JS 报错率、白屏率,并在跨应用跳转时串联链路日志——像保安巡逻一样,哪里冒烟就盯哪里。团队协作则需要定好“合同条款”:路由命名空间、props 协议、样式前缀规范,防止店铺之间互相越权。生态演进同样关键:iframe、Single-SPA、qiankun、Module Federation 各有适用场景,小团队硬上微前端,就像小卖部硬要修成购物中心,只会徒增物业费。

一次好的试营业,能把一场大火变成一次小烟头;一套成熟的治理体系,则能让商场在无数次日夜里平稳运转。

R全量=p,R灰度=g⋅p\displaystyle R_{\text{全量}} = p, \qquad R_{\text{灰度}} = g \cdot p
  1. 定义故障概率p 是新版本子应用出问题的概率,可以来自历史发布数据或线上监控。
    p∈(0,1)\displaystyle p \in (0, 1)
  2. 全量发布影响若 100% 用户进入新版本,故障影响面就是 p。
    R全量=p\displaystyle R_{\text{全量}} = p
  3. 灰度缩小影响假设只有 g 比例的用户进入新版本,故障影响面被压缩为 g 乘以 p。
    R灰度=g⋅p\displaystyle R_{\text{灰度}} = g \cdot p

AI 应用场景

智能脚手架生成器

阶段:代码生成 / 开发提效

解决的问题:每次新增一个子应用,都要手工配置基座接入、路由注册、qiankun 沙箱开关、CI 发布模板。传统方式重复劳动多、容易漏配。AI 可以基于少量描述自动生成完整子应用骨架和接入代码。

具体案例:开发者在 AI 助手中输入“创建一个 Vue3 子应用,挂载到 /user-center,样式前缀 uc-”,AI 自动生成 package.json、入口文件、qiankun 生命周期导出、路由配置和 Dockerfile。就像商场招商系统自动为品牌店生成装修图纸。

智能预加载预测

阶段:用户行为预测 / 性能优化

解决的问题:传统预加载依赖人工配置的规则(如 hover 某个菜单就预加载),既不精准又浪费流量。AI 可以学习用户历史点击路径,在用户还在当前页面时就预判下一个子应用并提前加载,把“商场人流调度”变成数据驱动。

具体案例:在大型 B 端管理后台,AI 分析用户每个工作日早上先打开“订单中心”再进入“对账中心”,于是系统在订单中心渲染完成时就悄悄预取对账中心资源,首屏时间降低 40%。

依赖冲突智能审计

阶段:代码分析 / 依赖审查

解决的问题:多子应用共享依赖时,版本冲突往往在运行时才暴露。AI 可以在 CI 阶段扫描各应用的 package.json 和 Module Federation 配置,自动生成共享版本建议或冲突报告。

具体案例:某团队 6 个子应用分别依赖不同版本的 lodash,AI 审计工具跑完 CI 后给出结论:“采用 lodash@4.17.21 可满足全部子应用,预计可减少 1.2 MB 重复加载”——相当于中央厨房的智能采购系统。

Python 演示

python72 行
# -*- coding: utf-8 -*-"""微前端最小模拟:快照沙箱 + Module Federation 版本协商"""from itertools import chain  class SnapshotSandbox:    """模拟 qiankun 的快照式 JS 沙箱"""     def __init__(self, name):        self.name = name        self.running = False        self.snapshot_map = {}        self.dirty_map = {}     def activate(self, global_state):        if self.running:            return        self.snapshot_map.clear()        self.dirty_map.clear()        for key in global_state:            self.snapshot_map[key] = global_state[key]        self.running = True     def write(self, global_state, key, value):        if not self.running:            raise RuntimeError("沙箱未激活")        if key not in self.dirty_map:            self.dirty_map[key] = global_state.get(key)        global_state[key] = value     def deactivate(self, global_state):        if not self.running:            return        for key in self.dirty_map:            global_state[key] = self.snapshot_map.get(key)        self.running = False  def resolve_shared_version(shared_specs):    """取被所有子应用接受的最大依赖版本号"""    libs = set(chain.from_iterable(spec.keys() for spec in shared_specs))    result = {}    for lib in libs:        candidates = set()        for spec in shared_specs:            if lib in spec:                lo, hi = spec[lib]                candidates.update(range(lo, hi + 1))        accepted = None        for version in sorted(candidates, reverse=True):            if all(lib not in spec or spec[lib][0] <= version <= spec[lib][1]                   for spec in shared_specs):                accepted = version                break        result[lib] = accepted    return result  if __name__ == "__main__":    global_state = {"theme": "light", "user": "guest"}    shop = SnapshotSandbox("shop-a")    shop.activate(global_state)    shop.write(global_state, "theme", "dark")    print("AppA 运行时:", global_state)    shop.deactivate(global_state)    print("AppA 卸载后:", global_state)     specs = [        {"react": (17, 18), "vue": (3, 3)},        {"react": (16, 18), "vue": (3, 3)}    ]    print("共享依赖版本:", resolve_shared_version(specs))
目的:用 Python 复刻 qiankun 快照沙箱的“拍照—恢复”逻辑,并模拟 Module Federation 的共享依赖版本协商。
  1. self.snapshot_map[key] = global_state[key]把全局状态拍照存进快照,这是沙箱能还原一切的“底片”。
  2. if key not in self.dirty_map:只记录第一次被改写的原值,避免重复记录浪费。
  3. global_state[key] = self.snapshot_map.get(key)卸载时用快照覆盖,恢复到开店前。
  4. candidates.update(range(lo, hi + 1))把所有应用可接受的版本枚举出来。
  5. all(lib not in spec or spec[lib][0] <= version <= spec[lib][1] for spec in shared_specs)验证某个版本是否被所有应用接受。

常见误区

误区用 iframe 把每个子应用包起来,天然隔离、实现简单,这就算微前端了。

正解iframe 确实隔离彻底,但缺点同样明显:页面间跳转割裂、弹窗和遮罩只围在框内、通信复杂、性能开销大、SEO 不友好。qiankun 用 JS 沙箱和样式隔离实现“像 iframe 一样安全,像原生页面一样流畅”的体验。

为何常见:iframe 是浏览器天然提供的隔离机制,上手最快,容易把“隔离”和“微前端”划等号。

误区基座外面又套了一层壳,每个子应用还要多一次加载,首屏肯定更慢。

正解微前端反而是按需加载的受益者。用户每时每刻只需要基座加当前子应用,比起巨石应用的全量加载,传输体积通常更小;配合预加载和 Module Federation 共享依赖,还能进一步加速。

为何常见:只看到多出来的调度层,没看到省下的其他子应用加载成本。

误区子应用用 Vue scoped 或 CSS Modules 加个唯一 class,就能高枕无忧。

正解scoped 只能约束组件内部,子应用动态插入的全局样式、body 级样式、第三方插件样式依然会污染其他应用。qiankun 的样式隔离会在卸载时移除动态 style 标签,才是完整的兜底。

为何常见:开发时只在自己应用里调试,没在基座上同时演示多个子应用,看不到真实冲突。

误区把所有依赖都标记为 shared,共享得越多,打包体积极小。

正解shared 会引入运行时版本协商和加载逻辑,配置不当会出现“版本不兼容导致重复加载”或“无法使用某应用需要的特定版本”,收益反而变负。共享要挑真正常用的基础库,并配合版本范围与 singleton 设置。

为何常见:从“不重复打包”的直觉出发,忽略了版本兼容的运行时成本。

误区微前端这么火,团队只有五个人也先上 qiankun 加 Module Federation,显得架构先进。

正解微前端解决的是大团队、多业务线、独立交付的治理问题。小项目或单团队落地只会增加基座维护、沙箱调试、部署链路等额外复杂度,属典型的过度设计。

为何常见:把流行技术当银弹,忽略了架构方案必须匹配团队规模与业务复杂度。

面试题

Q1. 微前端最核心的架构目标是什么?

单选题 · easy

  • A.用 iframe 套页面
  • B.独立开发部署子应用← 正确答案
  • C.React 换 Vue 框架
  • D.全部打成一个文件

答案:B。微前端把前端应用拆成可独立开发、独立部署、独立运行的子应用,由基座组合。A 只是实现手段,C 是技术栈替换,D 与微前端完全相反。用商场比喻:招商的本质是让品牌店独立经营,而不是让每个店都改卖同一种商品。

Q2. qiankun 中把子应用从“登记”带到“挂载”的流程叫什么?

单选题 · easy

  • A.生命周期← 正确答案
  • B.网格布局
  • C.路由劫持
  • D.依赖注入

答案:A。qiankun 遵循 register → load → mount → unmount 的生命周期流程,类似商家签约、进货、开店、打烊。网格布局是 CSS 概念,路由劫持只是其中一环,依赖注入是其他框架的设计模式。

Q3. Module Federation 最核心的能力是什么?

单选题 · easy

  • A.极端压缩代码体积
  • B.运行时共享模块依赖← 正确答案
  • C.自动生成 CSS 样式
  • D.用 Node 渲染页面

答案:B。MF 让应用在运行时加载其他构建产物的模块,并共享基础依赖,就像中央厨房统一供设备。压缩体积靠 minify,生成 CSS 靠预处理器,Node 渲染是 SSR 的职责。

Q4. qiankun 的快照沙箱在哪个时机记录全局状态快照?

单选题 · mid

  • A.子应用注册时
  • B.子应用构建时
  • C.激活挂载前← 正确答案
  • D.首次点击时

答案:C。快照沙箱在子应用 activate 时保存 window 全局状态,deactivate 时恢复,对应“开店前拍照、打烊后还原”。构建发生在服务端,注册和点击都不是窗口状态记录的准确时机。

Q5. 以下哪个属于子应用与基座通信的推荐方式?

单选题 · mid

  • A.改写 window 任意变量
  • B.props 加自定义事件← 正确答案
  • C.使用 alert 弹窗传参
  • D.将 Cookie 塞进 URL

答案:B。qiankun 推荐通过 props 向子应用传参,子应用用自定义事件回传,类似商场广播系统。直接改写 window 破坏沙箱隔离,alert 和 Cookie 方案既不安全也无法承载结构化数据。

Q6. 微前端中实现样式隔离的常见手段有哪些?

多选题 · mid

  • A.Vue scoped / CSS Modules← 正确答案
  • B.Shadow DOM 隔离← 正确答案
  • C.动态 style 挂载卸载← 正确答案
  • D.删除所有 CSS 文件

答案:ABC。Vue scoped/CSS Modules 提供 class 级隔离,Shadow DOM 提供浏览器级隔离,动态 style 标签挂载卸载是 qiankun 的兜底方案。删除所有 CSS 文件属于破坏性操作,不是隔离手段。

Q7. 某应用依赖 lodash@4,另一应用依赖 lodash@5,MF 无法协商出统一版本时会怎样?

单选题 · mid

  • A.两个版本同时加载← 正确答案
  • B.只加载 lodash4
  • C.抛错关闭浏览器
  • D.自动合并两个版本

答案:A。当 shared 版本不兼容时,MF 会退化为各应用加载自己的依赖副本,虽然造成重复加载,但至少保证功能可用。只加载一个版本会破坏另一应用的兼容性,抛错和自动合并都不符合运行时兜底逻辑。

Q8. 下列关于 qiankun 沙箱的说法正确的是?

多选题 · hard

  • A.记录改动后恢复现场← 正确答案
  • B.快照保存全部窗口← 正确答案
  • C.支持多实例并存← 正确答案
  • D.快照模式性能更优

答案:ABC。Proxy 沙箱只记录被修改的属性再恢复,快照沙箱会保存整个 window 状态,Proxy 沙箱因为不复制全量对象所以支持多实例并存。D 说反了,Proxy 沙箱通常比快照沙箱性能更优。

Q9. 微前端实践中的灰度发布与降级策略包括哪些?

多选题 · hard

  • A.按用户标识分流版本← 正确答案
  • B.挂载失败展示兜底页← 正确答案
  • C.全部回滚旧版本
  • D.按权重逐步放量← 正确答案

答案:ABD。按用户标识分流和按权重放量是典型灰度手段,挂载失败展示兜底页是降级容灾。全量回滚是最后的手段而非主动策略,一次性回滚也违背了灰度渐进的原则。

Q10. 在大规模 MF 体系中,要最可靠地避免重复加载并保证依赖单例,最推荐的做法是什么?

单选题 · extreme

  • A.全部标记共享不设版本
  • B.共享加单例与版本校验← 正确答案
  • C.各自内嵌依赖不共享
  • D.复制 node_modules 统一

答案:B。将基础依赖配置为 shared 并开启 singleton,配合语义化版本范围校验,是 Webpack 官方推荐做法,类似中央厨房统一供货且签订兼容合同。A 缺少版本约束可能静默不兼容,C 直接重复加载,D 在工程上无法维护。