SuperAPI AI 工具集

solid-js-2x-migration

编程与开发

查看项目

更新于 11-01 04:33

技能介绍

SolidJS 2.x Migration 是一个面向迁移的技能:当用户已拥有 Solid 1.x 代码并希望升级到 Solid 2.x beta 或 next 时使用。它的目标不只是解释新 API,而是尽可能安全地转换旧代码并保留原有行为。若用户只想了解某个 2.x 原语或警告、并非真正在升级代码,应改用 Solid 2.x API 技能。

用途与定位

适用场景包括升级、移植、转换、分阶段迁移计划,以及调试升级过程中或升级后出现的破坏。重点是把现有代码安全地迁移过去,而不是泛泛介绍 2.x API 全貌。若任务主要与 SolidStart 相关,应配合 SolidStart 技能使用,而不要依据通用 Solid 指导臆断框架边界。

迁移思路

把迁移视为两类工作:一类是大多较直接的机械式改动,另一类是需要仔细推理与验证的语义改动。不要把所有改动都呈现为同样安全,应明确指出哪些重写是机械式的、哪些可能改变行为。不得编造该技能迁移指导之外的替代 API;若候选重写依赖相邻框架辅助函数或不确定的 beta 导出,应明确说明,并把迁移保持在最高确定性的 Solid 核心路径上。

推荐迁移流程

检查包版本、导入语句以及当前对 1.x API 的使用;先做导入与包边界改动;迁移已移除或改名的 API;迁移对行为敏感的响应式模式;运行测试或至少仔细阅读开发警告;修复剩余的生态或工具链问题。

高确定性机械式迁移

优先处理:solid-js/web 改为 @solidjs/web;solid-js/store 导入改为来自 solid-js;solid-js/h 改为 @solidjs/h;solid-js/html 改为 @solidjs/html;solid-js/universal 改为 @solidjs/universal;Suspense 改为 Loading;ErrorBoundary 改为 Errored;Index 改为 For keyed={false};createSelector 改为 createProjection 或函数式 createStore;unwrap 改为 snapshot;mergeProps 改为 merge;splitProps 改为 omit;classList 改为 class;use: 指令改为 ref 指令工厂;attr: 和 bool: 改为标准属性行为;oncapture: 移除;onMount 改为 onSettled。即使是机械式迁移,也应快速核对周边语义,而不是盲目重写。另需注意非简单改名项:createResource 不是简单改名,应向异步计算加 Loading 迁移;startTransition 与 useTransition 被移除,需用内置 transition、isPending、Loading 和乐观原语表达待定与过渡体验;createComputed 被移除,应按意图替换而非按语法模式匹配。

典型前后对照

导入:1.x 从 solid-js/web 导入 render、从 solid-js/store 导入 createStore;2.x beta 从 @solidjs/web 导入 render、从 solid-js 导入 createStore。Index 改 For:For keyed={false} 的回调形态与 1.x Index 一致,item 是访问器、i 是普通数字;变化的是默认(keyed)For,现在传原始 item 和索引访问器 i()。Suspense 改 Loading、ErrorBoundary 改 Errored 时 fallback 签名保持一致。onMount 改 onSettled 应视为生命周期语义复核,尤其当旧挂载逻辑创建嵌套原语或假定 setter 后立即读取时。单回调 createEffect 改为计算/应用两段式,清理函数从应用段返回。顶层 prop 读取和组件顶层解构会触发警告,应把读取移入 JSX、memo 或 effect 计算函数。store 辅助函数改为 snapshot、merge、omit,其中 merge 下 undefined 是显式覆盖值而非跳过键。createSelector 改用 createProjection 的投影式派生状态。store 更新优先草稿式,storePath(...) 可作为兼容桥接而非最终风格。

需谨慎处理的语义

2.x 中读取不会立即观察到刚写入的信号值,测试或命令式代码在 setter 后立即读取可能需要 flush();应仅在测试或命令式 DOM 代码中窄范围使用,不要到处散布。createEffect 迁移时把被跟踪读取移入计算半段、副作用移入应用半段、清理从应用半段返回;若旧 effect 实为派生状态,应改用 memo 或派生原语。onMount 改 onSettled 需确认意图。Context.Provider 改为 context 作为 provider。createComputed 按意图替换:副作用改拆分 createEffect,可写派生状态改函数式 createSignal 或 createStore,只读派生改 createMemo。所有权方面,2.x 中在 owner 下创建的 root 默认归父级所有,若旧代码依赖事实上脱离的生命周期,应显式用 runWithOwner(null, ...) 脱离。ownedWrite: true(旧 beta 中称 pureWrite)只用于狭窄内部场景,不能用来压住迁移中的应用状态错误;当前版本在拥有的作用域内写入会在开发环境抛错,包在 untrack 中也无济于事。

异步数据与 mutation

不要只把 Suspense 改名 Loading 就结束。若应用依赖 createResource,应向异步计算加 Loading、待定指示和显式刷新模式迁移;区分初始加载用 Loading、再次更新用 isPending,需要刷新期间保留旧输出时用 latest。合理目标包括 createMemo(async () => ...) 做异步派生值,createStore(fn, initial) 或 createProjection(...) 做异步派生集合或键控协调结果。旧 UI 若需要 stale-while-refreshing 行为,用 isPending(() => expr) 并可选 latest(...) 建模。若旧应用用 startTransition 或 useTransition 处理 mutation 体验,应转向 action(...)、乐观原语和 refresh(...)。

生态与工具链注意

Solid 2.x beta 或 next 迁移可能需要临时兼容处理,尤其涉及测试库、包别名、SSR 打包、去重本地 Solid 版本、锁定 next 的包版本。若某依赖尚未跟上,应明确说明,并把框架迁移工作与生态破坏分开。实际项目经验包括:部分包仍需别名或临时配置调整;测试工具可能需要把 solid-js/web 别名到 @solidjs/web;链接的本地包可能需要 dedupe 设置以避免多份 Solid;beta 采用期 next 标签与临时覆盖可能是务实路径;开发警告常是语义迁移错误的首个准确信号;深度观察不再能随意撞上,若旧代码期待“观察一切”行为,可能需要显式 deep(store) 读取;加载与 mutation 状态不再那么依赖特定原语,旧的 .loading 和过渡包装模式多可收敛为 Loading、isPending、action 与乐观原语;意外依赖无主生命周期的旧代码可能表现更合理,但单例式集成现在应显式用 runWithOwner(null, ...) 脱离;作用域内写入与严格读取警告通常是设计反馈,不应压制。

按任务划分的迁移指引

分阶段迁移计划:先区分机械式改动与语义重写,尽早改导入与包边界,仅在降低风险时使用 storePath(...) 等兼容桥接,为警告清理和测试修复留出时间。组件代码:优先查找 Index 改 For keyed={false}、顶层 prop 读取与解构警告、onMount 假定需改 onSettled、Context.Provider 习惯、use: 指令需 ref 工厂。响应式模式:优先查找用 effect 做状态派生、memo 或其他被跟踪作用域中写信号或 store、假定 setter 后读取立即更新、假定脱离生命周期的嵌套 createRoot(...)。异步数据与 mutation:不要止步于 Suspense 改 Loading;把异步读取转向计算加 Loading;把 Loading 与 isPending 当作不同职责;把旧 transition 式 mutation 体验转向 action(...)、乐观原语与 refresh(...);把异步读与异步写作为独立迁移事项。调试测试与工具链问题:优先查找 setter 后立即读取的陈旧值、别名或包边界不匹配、链接包或 monorepo 中重复 Solid 版本、测试库或 SSR 工具生态滞后、揭示语义迁移错误而非语法错误的警告。

常见迁移错误

不要把每次迁移当作改名遍历,应区分机械改动与语义重写;不要只改 Suspense 名称却保留旧异步模型;不要把 createResource 视为一词替换,应向异步计算加 Loading、isPending 与 refresh(...) 迁移;不要仅因 1.x 中存在写回 effect 就保留它,若真实意图是派生应改用 createMemo 等派生形式;不要在测试失败后到处散布 flush(),应仅在确需稳定点时窄范围使用;不要把 storePath(...) 当作最终 2.x 风格。