一个产品里同时使用 Angular、React 和 Vue
Angular、React 和 Vue 可以同时运行在一个产品里。只有当它们继续作为技术上彼此独立的应用存在,并且组织收益足以覆盖一个 polyglot Frontend Platform 的长期成本时,这种选择才真正合理。
这些 Framework 不需要“彼此兼容”。
它们需要的是干净地并排运行。
这远不只是把不同 JavaScript Bundle 塞进同一个页面。每个 Framework 都需要自己的 DOM Area、自己的 State 和自己的 Lifecycle。Host 可以知道一个应用怎样启动、怎样结束,但不应该需要知道它内部如何 Render、如何管理 Dependency、如何组织 State。
因此,Framework Autonomy 并不是免费的优势。
它是一项需要长期供养的 Platform Decision。
而且成本不仅来自 Runtime、Build System 和 Know-how,也来自可见 UI。Framework 可以不同,但用户不应该感觉自己在三个应用之间来回切换。
三个 Framework,就是三个应用
Section titled “三个 Framework,就是三个应用”理解 polyglot Frontend 最清楚的方式,是不要把 Angular、React 和 Vue 当成可以互相替换的 Component Model,而是把它们视为共同产品中的独立应用。
Angular Host├── Angular 区域│ └── Angular Root├── React 区域│ └── React Root└── Vue 区域 └── Vue Root每个区域都有自己的 Runtime、Component Tree、Rendering Mechanism 与 Local State;会被独立启动,有自己的 Error Behavior,移除时也必须可靠 Cleanup。
Angular 按 Angular 的规则管理 Component。React 拥有自己的 Root,并控制下面那块 DOM。Vue 同样带着自己的 Component 与 Reactive Model。对 Integration 来说,真正重要的并不是这些模型具体有多像或多不同。
真正重要的是:谁拥有哪块区域。
Polyglot Frontend 不是靠“统一所有 Framework 的共同抽象”工作,而是靠清晰的技术 Ownership Boundary。试图把多个 Framework 的内部模型强行统一,并不会消灭差异,只会把差异藏进一个更难理解的 Integration Layer。
自己的 DOM、自己的 State、自己的 Lifecycle
Section titled “自己的 DOM、自己的 State、自己的 Lifecycle”Host 为 Remote 提供 Container。一旦 Remote Mount 进去,Container 下面的区域就完整属于对应 Framework。
Angular Host│├── Angular Root│ └── 只由 Angular 管理│├── React Mount Point│ └── 只由 React 管理│└── Vue Mount Point └── 只由 Vue 管理Angular Host 可以创建一个 Container 给 React App,并在之后把这个 Container 移除。但它不应该直接修改 React Root 内部的 DOM。同样,React Component 不应该访问 Angular Injector,也不应该控制 Angular Component Instance。
State Model 同样不应该跨过这条边界。Angular Service 不会自动变成 React Context,React Store 不应该由 Angular Component 直接修改,Vue Store 更不应该成为所有应用共同拥有的全局业务 State。
这种直接连接在一开始往往显得很务实:对象已经在内存里,两边反正都跑在同一个 Browser 中,直接引用还省掉一个 Contract。
实际上,这建立的是对另一个 Framework 和应用 Internal 的技术依赖。
Update、Test 和 Failure 很快就会把问题暴露出来。一个 Team 无法再自由改变自己的内部实现,因为必须考虑另一个应用。Lifecycle 相互依赖,Cleanup 变得模糊,Test 也需要同时启动多个 Framework,即使真正要验证的只有一个区域。
一个 Framework 可以 Mount 和 Unmount 另一个 Framework 的 DOM Area。
它不应该管理那个区域的内部实现。
Integration Contract 只需要知道开始和结束
Section titled “Integration Contract 只需要知道开始和结束”Integration 并不需要一个共同的 Component Standard。很多时候,一个很小、framework-neutral 的 Lifecycle Contract 就足够了:
interface RemoteApplication { mount(container: HTMLElement, context: PlatformContext): void; unmount(): void;}Host 因此知道 Container、启动入口和 Cleanup 入口,也可以传入一个很小的 Platform Context,并展示 Loading 或 Error State。
但它不认识 React Component、Hook 或 Context Object,不认识 Angular Injector,也不认识 Vue Component Instance。它更不需要知道 Remote 把 State 存在哪里,什么时候会重新 Render。
Host 知道应用如何启动和结束。
它不知道应用内部如何工作。
Contract 可以是 Async,可以返回 Failure State,也可以根据 Platform 增加其他 Lifecycle Operation。这些实现变体不会改变原则:边界描述的是“如何集成一个应用”,不是“如何远程操控它里面的 Component”。
Contract 越小,每个 Framework 在自己边界内就越能独立演进。
window 上的一个小 Contract
Section titled “window 上的一个小 Contract”某个真实项目里,一套 React App 被集成进 Angular Host 的方式非常直接:React App 在全局 window 上注册一小套 Contract。
window.reactRemote.mount(container, context);window.reactRemote.unmount();这从技术上看很粗糙。Global Object 必须有唯一 Name,Load Timing 必须可控,Bootstrap Failure 不能悄悄消失,Contract 要 Versioning,Cleanup 也不能忘。Test 还需要显式准备和清理这项 Global Registration。
所以,一个不断增长的 window Object 显然不应该成为普遍的 Production API。
但从架构角度看,这种 Contract 反而很诚实。Angular 不认识 React Component,React 不认识 Angular Service。两个 Framework 有分离的 Lifecycle,共享边界只有 DOM Container、Context、mount 和 unmount。
一个朴素、很小、framework-neutral 的 Contract,可能比“漂亮地把两个 Framework Runtime 缠在一起”更干净。
同样的 Contract 完全可以由受控 Registry、Loader 或其他 Integration Infrastructure 提供。技术载体可以升级,但边界本身不应该因此变得更通透。

Platform 共享 Contract,不共享 Framework Internal
Section titled “Platform 共享 Contract,不共享 Framework Internal”这些应用通常仍然需要一些共同 Platform Capability:Authentication、Navigation、Locale、Theme、Telemetry、Feature Configuration 和 Session Context 不可能每个 Remote 都完全独立解决。
但这些能力也不应该以 Angular Service、React Context 或 Vue Store 的形式直接公开。
Platform Contract├── Authentication├── Navigation├── Locale├── Theme├── Telemetry├── Feature Configuration└── Session Context这样的 Contract 应该小、稳定,并且 framework-neutral。它不传递 Component Instance,也不携带其他 Remote 的业务 State;不假设某个特定 Rendering Cycle,也不控制应用内部 Lifecycle。
每个 Framework 再把 Contract 翻译进自己的世界:
Framework-neutral Platform Contract├── Angular Adapter├── React Adapter└── Vue AdapterAngular Adapter 可以转换为 Angular 内部机制;React Adapter 可以暴露合适的 Context 或 Hook;Vue Adapter 则转换为 Vue 自己的结构。这些 Adapter 都留在各自应用内部。
这样,各 Team 仍然可以 idiomatic 地使用自己的 Framework,而 Platform 本身不会绑定到任何一个 Framework。
Polyglot Frontend 并没有减少 Standardization。
它只是把 Standardization 从 Framework 层移动到了 Integration Contract 层。
Framework 分离,不等于 Browser Sandbox
Section titled “Framework 分离,不等于 Browser Sandbox”分离 Root 可以建立清晰技术 Ownership Boundary,但不会产生完整 Isolation。
所有应用仍然处在同一个 window 和同一个 document 中,共享 Browser History 和页面 Main Thread。Network、Memory 与 CPU Resource 也都发生在同一个 Browser Environment 内。
所以仍然存在很多共同冲突面:
- Global Style 与 CSS Custom Property;
- Router 与 History;
body下的 Overlay 或 Portal;- Global Event Listener 与 Error Handler;
- Storage Key;
- Telemetry;
- Custom Element Registration;
- Network 与 Main Thread Load。
一个计算很重的 React 区域照样能卡住 Angular Host。Vue Remote 里的 Global Stylesheet 也可能影响自身 Root 之外的 Selector。Dialog 或 Tooltip 通过 Portal Render 时,可能跑到原本 Root 边界之外的 DOM 位置。
Framework Boundary 不是 Browser Sandbox。
这不是反对分离 Root,而是在说明:即便 Framework Boundary 很清晰,Shared Platform 仍然承担哪些共同责任。
Shadow DOM 只隔离问题的一部分
Section titled “Shadow DOM 只隔离问题的一部分”无论用什么 Framework,都可以把 Shadow DOM 作为额外 Integration Boundary:
Framework Mount Point└── optional Shadow Root └── Framework Root这样能更好控制 Local CSS Cascade。Global Selector 不会轻易进入封装区域,DOM Ownership 也更明显,一些命名和 Style 冲突可以避免。
但 React 并不会默认使用 Shadow DOM。Angular 或 Vue App 也不会因为存在于页面里,就自动被放进 Shadow Root。
更重要的是,Shadow DOM 不会创建新的 JavaScript Realm。Main Thread、Memory、Network、window、Storage 与 Framework Runtime 仍然共享,组织层面的维护成本也一个都不会消失。
同时,它还会引入新的 Integration Question:Portal 和 Overlay 如何跨边界;Focus Behavior、Form、Accessibility 与 Event Boundary 如何处理;Global Font、CSS Custom Property 与 Design Token 如何定义和继承;Test Tool 是否理解额外封装。
Shadow DOM 可以更强地封装 DOM 和 Style。
它不会把一个 Framework Area 变成独立应用或独立 Browser Context。
三个 Framework 会产生永久 Platform Cost
Section titled “三个 Framework 会产生永久 Platform Cost”技术上能不能启动,通常不是难点。Angular、React 和 Vue 都能启动。
难的是几年之后还能不能可靠运营。
每增加一个 Framework,就增加一套 Runtime、一个 Ecosystem 和一套 Development Model。
Angular├── Runtime├── Updates├── Build├── Testing├── Debugging└── Know-how
React├── Runtime├── Updates├── Build├── Testing├── Debugging└── Know-how
Vue├── Runtime├── Updates├── Build├── Testing├── Debugging└── Know-howRuntime 层面可能增加 Download、多次 Bootstrap、Memory Consumption 与 Main Thread Work。真实影响取决于应用和发布方式,但额外 Runtime 从来不是零成本。
通常更昂贵的是长期 Platform Cost。组织需要维护所有支持 Framework 的能力,计划多个 Ecosystem 的 Update 与 Security Fix,处理不同 Build、Test 与 Debugging 模型。Monitoring 和 Incident Analysis 还必须覆盖这些技术行为各不相同的应用。
除此之外,还有 Platform Adapter、Documentation、Onboarding 与 Shared Quality Rule。发生 Incident 时,必须有人既懂业务区域,也懂该区域使用的 Framework 和 Toolchain。
所以,关键不是“今天这个 Team 会不会第三个 Framework”。
关键是:五年之后谁来运营它?
也许原来的开发者已经离开,也许 Ecosystem 已经改变,也许业务区域很稳定,只偶尔 Maintenance。恰恰这种时候,仍然必须有人能做 Security Update、修 Build、分析 Production Error。
当一个 Framework 永久进入同一个 Product 与 Platform,它就不再只是某个 Team 的局部 Project Decision。

产品仍然必须感觉像一个产品
Section titled “产品仍然必须感觉像一个产品”Framework Autonomy 常被理解为减少技术规范:每个 Team 可以使用自己 Ecosystem 中成熟 Tool,在本区域独立决策。
用户看不到这些技术 Boundary。
他们使用的是同一个产品。因此 Color、Validation、Focus Management、Error Handling 不应该每切换一个 Remote 就明显变化,Accessibility 也不能取决于当前区域恰好由哪个 Framework Render。
团队在 Framework Flexibility 上节省的统一工作,可能以长期 UI / UX Harmonization 的形式重新回来。
Framework 技术上可以不同。
用户不应该因此觉得自己在不同产品之间切换。
“两边都用 Material”还不够
Section titled ““两边都用 Material”还不够”Angular Material 和 Material UI 是一个很直观的例子。两者都受类似 Design Language 影响,却并不代表它们放到同一个产品中就会自动表现一致:它们是不同 Library,拥有自己的 API、Default、Theme System 与 Release Cycle。在独立 Demo 页面里,两边各自都很一致;真正并排出现时,Spacing、Focus State 或 Label Behavior 的差异会立刻明显。
这不是两套 Library 的质量比较。问题只发生在一个错误期待上:相似的 Design Origin 可以替代共同 Product Design。
“两边都用 Material”还不是共同 Design System。
这里与 Authentication 或 Navigation 的 Platform Contract 是同一个原则:Angular Host 不能把自己的 Angular Material Theme Object 直接当成整个 Product Contract,因为 React 或 Vue 无法使用它的内部模型。共同模型必须位于 Framework 之上,再由每个 Framework Adapter 翻译——Product 拥有 Design System,Framework 只拥有 Adapter。
因此,Technology Autonomy 也不是建立多个视觉产品的许可证。不同 Framework 内部可以有不同技术实现,但可见产品允许什么差异,是另一项 Governance Decision。关于 Design Token、Interaction Pattern 以及合理 UI Autonomy 的边界,可以继续阅读一个产品能承受多少 UI 自治?。
不要给每个 Framework 都自建一套 Component World
Section titled “不要给每个 Framework 都自建一套 Component World”理论上,可以通过自建 UI Kit 消灭多个 Component Library 的视觉差异:
自建 Angular UI Kit+自建 React UI Kit+自建 Vue UI Kit这样做的结果,并不是维护一套共同 Component Library,而是运营多套自研 Component Platform。
每一套实现都需要承担 Accessibility、Test、Documentation、Bug Fix 和 Update。Combobox、Table、Date Picker、Dialog 这类复杂 Component 需要多次开发,并在多年内保持能力相近。每出现一个新 Product Requirement,就会产生 Framework 之间的 Parity Work。
对于品牌非常核心或业务关键的 Component,自建多实现可能合理。
但它不应该成为每一个第三方 Library 小差异的默认答案。
更务实的办法通常是:每个 Framework 使用成熟 Component Library,在它们之上定义 framework-neutral Design System,再在合理范围内配置这些 Library。只要产品整体仍然连贯、可预测,小差异可以有意识地接受。
目标不是绝对 Pixel Identity。
目标是行为一致和共同 Product Language。
为了不同 Component Library 之间的 Pixel-perfect Parity,最终花掉的成本可能比最初获得的 Framework Freedom 还高。
什么时候多个 Framework 可能合理
Section titled “什么时候多个 Framework 可能合理”这些额外成本并不意味着 Polyglot Frontend 天然错误。
已有产品可能携带另一套 Stack,需要逐步集成到新 Platform。收购来的系统继续运营,可能比完全重写更经济。某项业务独立 Capability 也可能已经拥有成熟 Team 和长期可用 Know-how。
特殊技术要求同样可能证明不同 Stack 合理。边界清晰的 Experiment 也可以有价值,只要 Goal、Owner 与 Evaluation 已经明确。前提始终是 Platform 明确准备好承担这套额外 Stack。
稳定的组织边界会让这种选择更容易。拥有长期 Ownership 的独立区域,可以承担自己的 Stack。频繁重组 Team、职责模糊,则是明显反对因素。
但不是每个局部偏好都有经济理由。
一个 Team 更喜欢 React 而不是 Angular;另一个想尝试 Vue;某个新 Framework 看起来热门或者更容易 Recruiting;一个小功能用另一个 Stack 似乎更快。
这些理由主要看第一批开发成本,却没有回答:谁维护 Integration、谁做 Security Update、谁维护 Design System Adapter、几年后谁接手?
Framework Autonomy 只有在解决真实的组织、业务或经济问题时才有价值,而不是把局部偏好制度化。
谁承担成本?
Section titled “谁承担成本?”新增 Framework 的收益通常发生在局部。
Team 可以使用熟悉技术,复用 Know-how,自主决定 Tooling,因此该区域的开发可能更快、更可靠。
额外成本却散落在多个地方。
Platform 需要维护 Integration Contract、Framework Adapter、Build / Test System、Observability、Security Update 和 Documentation;需要在多个 Component World 之间统一 UI / UX,并在 Incident 中提供 Support。
Product 还承担额外 Runtime、Download 与潜在不一致。如果 Harmonization 不够可靠,用户会直接体验到 Interaction Detail 或 Accessibility Quality 的差异。
因此,一个决策对局部 Team 明显是正收益,对整体 Product 仍然可能是负收益。
只有当 Team 的局部收益大于新增 Platform 与 Product Cost 时,它才是系统级收益。
这项权衡不能只由想引入新 Stack 的 Team 决定,因为它直接获得收益,却不一定承担全部长期成本。
新 Framework 应该有进入门槛
Section titled “新 Framework 应该有进入门槛”对于新区域,一个 Standard Framework 应该继续是默认选择。共同 Standard 不会消灭所有技术问题,但至少限制了组织需要长期运营的 Ecosystem 数量。
额外 Framework 应该需要明确业务、组织或经济理由,而且这个理由必须比个人偏好或短期 Productivity 更强。
一旦允许新增 Framework,就必须有清楚边界:它完整留在自己的 DOM Area,自行管理 State,拥有独立 Lifecycle;Framework Internal 不跨越边界。
Host 只认识很小的 framework-neutral Lifecycle 与 Platform Contract。Authentication、Navigation、Locale、Theme 与 Telemetry 作为稳定 Platform Capability 提供,然后在各 Framework 内部 Adapter。
Design System 位于 Framework 之上。每个被支持的 Component World 都需要维护 Theme 与 UX Adapter。成熟 Library 应该保持为默认选择,自建 Component 只在 Product Value 足以覆盖长期成本时出现。
最重要的是,每个 Framework 都必须有长期 Ownership。Update Strategy、Security Responsibility、Support 与 Know-how 要在一个局部 Experiment 变成 Product Platform 的正式组成部分之前说清楚。
Framework Autonomy 需要准入门槛。
引入新 Framework 的人,不只要解释第一个 Use Case,还要解释它如何长期运营。
Angular、React 和 Vue 能够运行在同一个产品里,因为每个 Framework 管理自己的 UI 区域。它们不需要彼此理解。只要 Framework Internal 不跨越边界,这种分离就能够成立。真正共享的不是 Component、Store 或 Rendering Cycle,而是很小、稳定的 Platform Contract。
分离 Root 带来清晰 Ownership Boundary,却不会创造 Browser Sandbox。与此同时,组织必须长期运营多套 Runtime、Toolchain 和 Know-how。成本不会在第一次 Bootstrap 成功之后消失。
Design System 也必须被翻译到多个 Component World。Angular Material 与 Material UI 这样的相似 Library 不会自动产生相同 UI / UX。Visual Token 还需要配套行为规则和长期维护的 Adapter,才能让技术多样性不变成用户眼里明显不同的多个产品。
因此,Framework Autonomy 只有在具体收益能够覆盖这些长期 Platform Cost 时才合理。
多个 Framework 不是几个 Team 的技术玩具。
它们是整个 Platform 的长期投资。