react-spectrum S2 迁移实战:codemod 运行之后,如何完成剩余的手动修复

react-spectrum S2 迁移实战:codemod 运行之后,如何完成剩余的手动修复 react-spectrum S2 迁移实战codemod 运行之后如何完成剩余的手动修复【免费下载链接】react-spectrumA collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.项目地址: https://gitcode.com/GitHub_Trending/re/react-spectrum本篇基于 react-spectrum 仓库内置的 S2 迁移手动修复参考文档系统讲解s1-to-s2codemod 运行结束后需要人工介入的六类典型问题图标与插图替换、Flex/Grid/View/Well布局组件移除、UNSAFE_style/UNSAFE_className迁移到 style macro、Dialog 关闭逻辑重排、集合组件中Item的改名以及 Toast 的导入迁移。读完本文你可以对照仓库中 codemod 的源码与测试确认每一处TODO(S2-upgrade)标记应如何消除并将 v3S1代码完整落到react-spectrum/s2。背景codemod 的自动化边界与 TODO(S2-upgrade) 标记react-spectrum 提供了一个名为 Upgrade Assistant 的 CLI 工具用于把 React Spectrum v3即 S1组件升级到 Spectrum 2S2。根据 升级助手 README其用法为npx react-spectrum/codemods s1-to-s2支持的选项-c, --components components逗号分隔的待升级组件列表例如Button,TableView不指定则升级全部已实现 codemod 的组件--path path执行 codemod 的目录默认为当前目录-d, --dry只预览不写盘--agent非交互模式跳过交互提示、包安装和 macro 配置适用于 CI 或 Agent 场景前提react-spectrum/s2已安装且可解析。该工具基于 jscodeshift 实现每个组件对应一个 transform见 codemods/components 目录 下Button/transform.ts、TableView/transform.ts等文件。关键在于codemod 无法覆盖所有场景。从 主 codemod 入口 可以看到它在无法自动处理时会向代码注入注释标记例如动态导入无法处理时TODO(S2-upgrade): check this dynamic import图标在 S2 中没有对应项时TODO(S2-upgrade): A Spectrum 2 equivalent to ${name} was not found. Please update this icon manually.插图无对应项时TODO(S2-upgrade): A Spectrum 2 equivalent to ${name} was not found. Please update this illustration manually.。而 CLI 入口 在完成转换后输出的 Next steps 中明确把「搜索TODO(S2-upgrade)并逐一解决剩余的手动迁移项」列为下一步。本文其余章节就是逐类处理这些标记的方法。图标与插图在标记处手动挑选最近的 S2 替代迁移参考文档给出的规则很直接如果 codemod 在某个图标或插图导入旁边留下了TODO(S2-upgrade)请手动挑选最近的 S2 替代项。之所以会产生这种标记是因为 codemod 依赖两张静态映射表做自动替换图标映射表例如Alert→AlertTriangle、AlertCircle→AlertDiamond、Audio→MusicNote、At→Mention、BookmarkSmallOutline→Bookmark插图映射表。映射表命中的导入会被自动改写未命中的则按上文的规则留下TODO(S2-upgrade)注释。处理方式是在react-spectrum/s2的图标/插图集合中按语义名称、视觉形状、用途挑选最接近的替代项手动替换导入名并删除 TODO 注释。由于图标命名体系在 S2 中发生了变化如123→TextNumbers、Beaker→BetaApp建议对照 S2 图标索引逐个确认而不是仅凭直觉猜测。布局组件Flex、Grid、View、Well 的 div 化文档明确指出Flex、Grid、View和Well不属于 S2需要改为用 style macro 加样式的div元素。这与仓库中 UPGRADE.md 迁移指南 对 Flex/Grid/View 的说明一致UpdateFlexto be adivand apply flex styles using the style macro 等。style macro 的导入方式为 import attributes 语法import {style} from react-spectrum/s2/style with {type: macro};Flex 示例Before:Flex directioncolumn divItem 1/div divItem 2/div divItem 3/div /FlexAfter:import {style} from react-spectrum/s2/style with {type: macro}; div className{style({display: flex, flexDirection: column})} divItem 1/div divItem 2/div divItem 3/div /divGrid 示例Before:Grid justifyContentcenter divItem 1/div divItem 2/div divItem 3/div /GridAfter:import {style} from react-spectrum/s2/style with {type: macro}; div className{style({display: grid, justifyContent: center})} divItem 1/div divItem 2/div divItem 3/div /divView 示例View本身不承担布局职责直接替换为div即可// Before View Content /View // After div Content /divWell 示例Well带有一组内建外观边框、内边距、字号等需要把这些视觉属性用 style macro 显式表达出来// Before Well Content /Well // After import {style} from react-spectrum/s2/style with {type: macro}; div className{style({ display: block, textAlign: start, padding: 16, minWidth: 160, marginTop: 4, borderWidth: 1, borderRadius: sm, borderStyle: solid, borderColor: transparent-black-75, font: body-sm })} Content /div注意 macro 中取值与 CSS 的差异padding: 16是像素数字、borderRadius: sm是 S2 的设计令牌名、font: body-sm是 S2 的字体档位。style macro 支持的 CSS 属性集合以仓库内的 style macro 规则说明 与 S2 样式文档为准。UNSAFE_style 与 UNSAFE_className迁移到 style macro文档要求尽可能把UNSAFE_style的用法迁移到 S2 style macroUNSAFE_className同理支持的 CSS 属性清单见 S2 styling 文档。从源码看codemod 在 styleProps 转换器 中处理这些属性能自动转换的直接改写不能的则注入TODO(S2-upgrade): check this UNSAFE_style、TODO(S2-upgrade): check this UNSAFE_className或TODO(S2-upgrade): update this style prop注释遇到 spread 展开属性时还会标记check this spread for style props。因此处理步骤是全局搜索UNSAFE_style、UNSAFE_className与上述 TODO 注释将内联样式对象/类名映射为style({...})调用放入组件的className或 S2 组件的styles属性对照 UPGRADE.md 中的 Style props 章节完成 v3 令牌值到 S2 取值的换算。UPGRADE.md 给出了完整的换算表例如边框宽度none→0、thin→1、thick→2、thicker→4、thickest→[8px]圆角xsmall→[1px]、small→sm、regular→default、medium→lg、large→xl断点base→default、S→sm、M→md、L→lg。尺寸类属性width、padding、margin、gap等则需要按size-*/static-size-*令牌表换算为像素数字如size-200→16、size-500→40、size-1000→80。Dialogs关闭逻辑在 Dialog / DialogTrigger / DialogContainer 之间的重排文档提示DialogContainer和useDialogContainer在 S2 中仍然存在但 dismiss关闭逻辑可能需要在Dialog、DialogTrigger、DialogContainer三者之间移动。从 codemod 源码可以印证这个变化的处理方式。transforms.ts 中的 moveRenderPropsToChild 函数负责把 render props 从DialogTrigger的 children 移动为Dialog的子级它能识别形如({close}) Dialog.../Dialog的箭头函数子节点自动把close参数改为对象解构{close}并移除Dialog上的onDismiss当渲染函数结构无法识别时则留下TODO(S2-upgrade): Could not automatically move the render props. Youll need to update this manually.或标记update this dialog to move the close function inside。结合 UPGRADE.md 的 Dialog/DialogTrigger 条目手动处理的口径是将 render props 从DialogTrigger的第二个子元素移到Dialog内部删除Dialog上的onDismiss改用DialogTrigger上的onOpenChange或DialogContainer上的onDismiss删除DialogTrigger的targetRefclose函数在 S2 中属于Dialog侧的 render prop。对于useDialogContainer的命令式打开场景需确认返回的open回调签名是否仍然匹配若 codemod 留下了 TODO 标记按上述三个角色的分工手动调整即可。CollectionsItem 按父组件改名并注意 id 要求当Item在 codemod 后仍然存在时即父组件结构无法被自动识别或落在映射范围之外需要按父组件手动改名。迁移文档给出的映射表如下Parent componentv3 childS2 childMenu / ActionMenuItemMenuItemPickerItemPickerItemComboBoxItemComboBoxItemTabsItemTab / TabPanelTagGroupItemTagBreadcrumbsItemBreadcrumb这一点在 Item 转换器源码 中有直接对应codemod 通过updateComponentWithinCollection依次尝试 Menu/ActionMenu/ContextualHelpTrigger →MenuItem、TagGroup →Tag、Breadcrumbs →Breadcrumb、Picker →PickerItem、ComboBox →ComboBoxItem、ListView →ListViewItem的改名并把key转换为id若渲染在array.map中则同时保留key以满足 React 要求父集合无法识别时调用commentIfParentCollectionNotDetected留下TODO(S2-upgrade): Couldnt automatically detect what type of collection component this is rendered in.这正是需要人工介入的信号。文档还强调了两条实操要求映射数组时保留 Reactkey但要确保集合数据项在 S2 期望的地方暴露idS2 集合文档有详细说明Table 和 ListView 的迁移通常需要人工复查行头row headers、嵌套列nested columns和显式 item id。从源码看这并非空话TableView 转换器 会针对以下情况留下 TODO 标记——找不到TableHeader导致无法推导columnspropCould not find TableHeader within Table to retrieve columns prop、行项缺少idyoull need to add an id prop to the Row、嵌套ColumnNested Column components are not supported yet、以及需要手动指定isRowHeader的列。对应地table.test.ts 与 listview.test.ts 固化了这些转换行为的预期输出可用于验证自己的修改是否与 codemod 语义一致。Toast 迁移导入路径、共享容器与队列调用文档对 Toast 给出了六条具体操作这里完整继承并结合仓库证据展开把ToastContainer和ToastQueue的导入从react-spectrum/toast改为react-spectrum/s2保持一个共享的ToastContainer挂载在应用根部或测试 harness 附近然后把所有队列调用更新为 S2 导入路径S2 支持ToastQueue.neutral、ToastQueue.positive、ToastQueue.negative与ToastQueue.info四种类型导入迁移后重新检查timeout、actionLabel、onAction、shouldCloseOnAction、onClose等选项在 S2 下的行为队列方法仍然返回 close 函数——如果现有交互依赖编程式关闭例如点击后立即消失务必保留这段逻辑移动导入后搜索所有ToastContainer挂载点和所有ToastQueue调用点——共享应用根部、次级入口点secondary entrypoints和测试 harness 是极易遗漏的位置。第 6 条与仓库中 迁移前检查清单 的建议互相印证该清单要求在迁移前就找到所有入口点包括独立页面、备用渲染根、内嵌子应用、仅测试用渲染目标并定位共享测试包装器、toast 配置同时把ToastContainer、ToastQueue、DialogContainer、useDialogContainer、UNSAFE_style等列为 codemod 之后的常见后续处理项。也就是说多入口项目例如仓库中 examples 目录下的多个独立应用在迁移时应先枚举入口再逐一核对 Toast 挂载与调用避免某个子应用残留旧导入路径。收尾自检清单完成上述各类修复后建议按 codemod 自身的 Next steps 口径做一遍自检确认react-spectrum/s2已安装且打包器支持 style macroParcel v2.12.0 原生支持Vite、webpack、Next.js、Rollup、ESBuild 等需通过unplugin-parcel-macros类插件接入且保证 macro 插件在其他插件之前运行若需要在入口组件添加import react-spectrum/s2/page.css;与 v3 不同S2 不再需要 Provider全局搜索TODO(S2-upgrade)确认标记清零全局搜索adobe/react-spectrum、react-spectrum/*非 s2、spectrum-icons/*的残留导入运行项目的 linter / formatterESLint、Prettier清理 codemod 产生的格式残留。注意 前置检查清单 给出的最低工具版本TypeScript 5.3解析with {type: macro}语法、Babel 7.27.0 或babel/plugin-syntax-import-attributes、ESLint 9.14.0 配typescript-eslint/parser、Prettier 3.1.1否则 import attributes 语法本身会导致解析或格式问题。以上流程覆盖的正是 focused-manual-fixes.md 所定义的全部手动修复面。配合 UPGRADE.md 完整迁移指南按组件列出 prop 级变更与 codemods 测试快照可对照 codemod 对各类组件的预期转换结果即可完成从 S1 到 S2 的完整迁移。【免费下载链接】react-spectrumA collection of libraries and tools that help you build adaptive, accessible, and robust user experiences.项目地址: https://gitcode.com/GitHub_Trending/re/react-spectrum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考