
微前端迁移先拆流程再切流量迁移对象不是一批文件从旧前端单体转向微前端真正需要拆的是路由、状态、样式、事件和发布责任。若只按目录或页面裁切隐藏在window、共享 store、全局 CSS 和构建插件里的依赖仍会跨越边界。仓库变多了运行时关系却没有变清楚。一次性迁移会放大隐藏依赖、样式冲突、事件清理和生成代码边界遗漏等风险。应先在代表性路由中验证这些场景并保留可回退的旧实现。迁移前先选一条业务流程从入口到交付记录当前行为。旧模块读取哪些状态、发出哪些事件、打开何种弹层刷新和返回时如何恢复都需要进入验收清单。新旧实现能用同一批场景核对才有逐步切换的基础。拆分时常见的偏差1. “大爆炸式”全量物理切分一次改变仓库、运行时、路由和发布流程会让差异难以归因。先定义应用边界与契约再决定是否需要独立仓库。共享 React 运行时和公共工具的版本策略也要提前确定不能等各子应用分别发布后再靠临时兼容收拾。2. 忽视遗留流程Legacy Flow的沙箱隔离旧系统可能直接读写window、操作全局 DOM 或依赖没有命名空间的样式。沙箱和 CSS 隔离能减少一部分冲突却不能自动识别业务共享状态。迁移清单要列出全局变量、事件监听、定时器和弹层挂载点并验证卸载后都得到清理。3. 盲目相信 AI 的“一键旧代码重构”模型可以协助定位旧 API 或生成候选改写但它无法从一个组件文件推断所有隐式依赖。生成结果先作为普通补丁审查逐项对照 Props、事件、路由和副作用。无法解释的改动应缩小范围而不是继续让模型重写更多文件。用路由开关保持双轨可比基座可以保留路由选择权通过稳定配置决定某个用户或任务使用旧模块还是新模块。分流键要稳定避免同一会话来回切换开关状态、应用版本和错误记录也要关联出现问题时才能确定用户实际走了哪条路径。自动降级需要结合状态语义。只读页面加载失败时回到旧模块通常较简单已经提交表单或修改本地状态后再切换可能重复操作或丢失输入。每条路由应分别说明允许降级的阶段不要把“捕获异常就切回”当作通用安全方案。静态分析可帮助列出 Props 与事件名称但不能证明行为相同。契约测试、端到端流程和人工检查应共同使用。模型在其中适合整理差异和生成候选用例不负责宣布迁移完成。一个 TypeScript 路由器示例下面的StranglerMigrationRouter展示动态加载、分流与错误回退的基本结构。它省略了生产环境需要的稳定分流键、模块地址白名单、加载取消、状态迁移和观测关联代码中的随机分流会导致重新挂载后路径改变因此只能作为接口草图。超时值与灰度比例也应来自项目配置和验证结果。import React, { Component, ReactNode } from react; /** * 路由迁移配置接口 */ export interface MigrationRouteConfig { path: string; legacyComponent: React.ComponentType; microAppUrl: string; enableMicroApp: boolean; grayScalePercentage: number; // 灰度比例 (0 - 100) } interface State { useMicroApp: boolean; hasError: boolean; isMicroAppLoading: boolean; MicroComponent: React.ComponentType | null; } /** * 绞杀者模式平滑迁移代理组件 */ export class StranglerMigrationRouter extends Component{ config: MigrationRouteConfig }, State { constructor(props: { config: MigrationRouteConfig }) { super(props); this.state { useMicroApp: false, hasError: false, isMicroAppLoading: false, MicroComponent: null, }; } componentDidMount() { this.evaluateTrafficStrategy(); } /** * 决定走旧单体还是微前端 */ private evaluateTrafficStrategy() { const { config } this.props; if (!config.enableMicroApp) { this.setState({ useMicroApp: false }); return; } // 根据灰度百分比计算 const randomVal Math.floor(Math.random() * 100); const shouldHitMicro randomVal config.grayScalePercentage; if (shouldHitMicro) { this.loadMicroAppModule(); } else { this.setState({ useMicroApp: false }); } } /** * 动态加载微前端子应用资源 (含超时熔断控制) */ private async loadMicroAppModule() { const { config } this.props; this.setState({ isMicroAppLoading: true }); const timeoutPromise new Promise((_, reject) setTimeout(() reject(new Error(MicroApp Load Timeout)), 3000) ); try { // 模拟动态加载微前端 Component (如 SystemJS / Module Federation Import) const loadPromise import(/* webpackIgnore: true */ config.microAppUrl); const module: any await Promise.race([loadPromise, timeoutPromise]); this.setState({ useMicroApp: true, MicroComponent: module.default || module, isMicroAppLoading: false, }); } catch (error) { console.error([Migration Alert] 微前端模块加载失败紧急降级回旧单体: ${config.path}, error); // 触发自动降级兜底 this.setState({ useMicroApp: false, hasError: true, isMicroAppLoading: false, }); } } /** * React Error Boundary 捕获微前端子应用运行期崩溃 */ static getDerivedStateFromError(error: Error): PartialState { console.error([Migration Alert] 捕获到微前端子应用渲染崩溃自动降级:, error); return { useMicroApp: false, hasError: true }; } componentDidCatch(error: Error, errorInfo: React.ErrorInfo) { // 可在此处上报日志到监控系统 (如 Sentry) } render() { const { config } this.props; const { useMicroApp, isMicroAppLoading, MicroComponent } this.state; const LegacyComponent config.legacyComponent; if (isMicroAppLoading) { return div classNamemigration-loading-spinner正在加载微应用.../div; } // 优先渲染微前端应用 if (useMicroApp MicroComponent) { return ( div classNamemicro-app-sandbox-wrapper>迁移阶段关键动作AI 辅助角色确定性质量防护手段梳理期扫描全局变量、样式和依赖链汇总候选依赖与待确认项AST 结果与人工流程回放相互核对接入期在一个代表性路由保留新旧选择生成路由配置草案使用稳定分流键验证加载、卸载和旧路由回退重构期拆模块并保持外部契约生成候选改写和测试清单对照 Props、事件、状态和关键用户流程扩展期按路由和用户范围逐步切换归类脱敏错误摘要每一档写明暂停条件演练回退后再扩大收尾期下线旧路由与临时适配检查残留引用确认调用方、监控和文档已指向新模块回退与下线都要实际验证回退不是开关存在就算完成。测试环境应演练新模块加载失败、运行中报错、用户已有输入和权限变化等情况确认哪些状态可以保留哪些必须提示用户重新操作。日志记录路由、版本和请求标识不保存表单敏感内容。新路由稳定后也不要立即删除旧实现。等调用方登记完成、关键流程对照通过、监控能区分模块版本再清理旧 Bundle、事件桥和兼容样式。微前端迁移的成果不是子应用数量而是每个应用的职责、契约与退出方式都比迁移前清楚。