资讯动态

RxJS 7 到 RxJS Next 冷观察者迁移实战:app-cold-strong 资格认证全流程剖析

发布时间:2026/9/19 23:10:55 来源:尧图企业网站定制
RxJS 7 到 RxJS Next 冷观察者迁移实战app-cold-strong 资格认证全流程剖析【免费下载链接】rxjsA reactive programming library for JavaScript项目地址: https://gitcode.com/gh_mirrors/rx/rxjs导读本文基于本仓库RxJS Next 迁移工具链中 P0.M5 资格认证最终报告 及其配套证据契约清单、命令记录、迁移补丁完整还原一次将应用从 RxJS 7.8.1 迁移到 RxJS 8.0.0-alpha.14 的冷cold观察者场景。你将掌握什么是producer-per-direct-subscription生命周期契约、迁移引擎rxjs-migrate的 dry-run/写入双阶段用法、ColdObservable、符号键map、addTeardown与 AbortSignal 取消在迁移中的具体落法以及如何通过受保护测试与控制项controls守住行为基线。场景背景P0.M5 与 app-cold-strongP0.M5 是仓库中针对packages/migrate迁移技能skill设计的资格认证qualification级别app-cold-strong是其中一个验收场景代表应用app 冷语义cold 强证据strong的迁移样本。该场景的评估结论为completed即全部要求的控制项满足、无产品缺口、无分叉、无阻塞项属于一次干净通过的冷观察者迁移。资格认证工作区位于 packages/migrate/test/agent/qualification-runs/2026-08-01/app-cold-strong/其中包含 6 个工件final-report.md最终报告本文核心骨架contract-manifest.json版本化的迁移契约清单schema 校验通过、readiness 为readyrecord.json完整评估记录含 gate 向量、决策向量、host 信息command-results.md各阶段命令与退出码表格patch.diff实际应用的迁移补丁conversation.mdAgent 对话摘要。// 来自 record.json 的关键身份信息节选 { runId: app-cold-strong--codex, scenarioId: app-cold-strong, sourceIdentity: { revision: npm:rxjs7.8.1 }, engineIdentity: { version: 8.0.0-alpha.14 }, conclusion: completed }迁移契约冷生命周期 一次订阅一个生产者本次迁移的核心不是换个 import 路径而是为可观察对象生命周期做出明确决策。SKILL.mdpackages/migrate/skill/SKILL.md强调绝不根据语法、文件名、操作符名或当前通过的输出去推断平台共享platform sharing还是每次直接订阅一个生产者producer-per-direct-subscription。生命周期意图必须由开发者显式批准引擎只负责在批准的契约内做有界重写。app-cold-strong 场景被批准的决策为decision:cold-lifecycle - producer-per-direct-subscription对应的契约单元contract-manifest.json 中units[0]单元 idrequest-cold-producer生命周期producer-per-direct-subscription证据分类portable可移植批准人scenario developer批准时间 2026-08-01T01:35:34Z该单元声明的行为主张claims包括每次直接订阅都会启动一个独立生产者生产者把源值 21 映射后发出 42取消一次订阅只关闭它自己拥有的生产者生产者 teardown 记录stop必须先于外层订阅 teardown 记录outer-stop证据是test/request.test-source.ts中的PT-COLD-INDEPENDENT、PT-COLD-CANCELLATION、PT-COLD-TEARDOWN三个受保护测试。契约清单同时记录了intentionalDivergences: []无有意分叉与diagnostics: []无诊断说明迁移没有改变任何受保护的既有期望。八阶段工作流迁移不是一次 codemod整个资格认证严格遵循 SKILL.md 定义的八个阶段。SKILL.md 开宗明义把这次迁移当作经过评审的项目工作而不是一次 codemod 运行——一个被转换的文件、一个干净的 diff 或一个通过的测试都不足以证明迁移完成。阶段目标app-cold-strong 中的落地1. 建立权威与范围记录仓库根、边界、写权限、包管理器、网络策略、候选门禁rxjs-migrate-skill check校验已安装 Skill 与规范 SHA-256 一致2. 评估用法与生命周期风险盘点 Observable 构造、订阅所有权、取消、teardown 等敏感路径定位到src/request.ts的冷生产者单元3. 建立绿色 RxJS 7 基线在未改动项目上跑通 build/testRxJS 7.8.1pnpm run build与pnpm test均通过4. 分类并批准目标契约每个单元记录目标生命周期与证据分类批准producer-per-direct-subscription5. 规划并 dry-run 有界引擎变更先跑确定性引擎不写入2 个变更计划0 诊断精确选中operator.map能力6. 应用一个小批量只应用已评审的 dry-run 计划写入src/request.ts与test/request.test-source.ts7. 构建、测试、诊断、修复分类失败并按规则修复发现并修复 1 个 teardown 顺序缺陷8. 收尾与交接更新契约清单、报告校验 schema 与 readinessreadinessready无 findings建立绿色基线RxJS 7.8.1 的 build 与受保护测试迁移前的任何改动都不允许发生。Stage 3 要求先在未改动的 RxJS 7.8.1 项目上运行约定的 build、type、lint、单元与行为检查并记录精确命令、环境事实、退出码与结果。来自 contract-manifest.json 的基线记录{ id: rxjs7-build, command: pnpm run build, environment: { node: v24.12.0, pnpm: 10.26.0, rxjs: 7.8.1, network: disabled }, status: passed, exitCode: 0, summary: TypeScript compiled successfully against unchanged RxJS 7.8.1 after adding the value characterization assertion. }, { id: rxjs7-tests, command: pnpm test, environment: { rxjs: 7.8.1, framework: vitest 1.2.1, network: disabled }, status: passed, exitCode: 0, summary: One file and all three protected tests passed; PT-COLD-INDEPENDENT also characterized emitted value 42. }关键环境事实Node v24.12.0、pnpm 10.26.0、vitest 1.2.1并且网络被禁用——整个迁移必须在离线状态下完成这保证了依赖解析完全来自仓库本地授权的 tarball而非注册表。测试框架选择preserve保留 vitest因为开发者没有要求单独的框架转换。引擎 dry-runrxjs-migrate的确定性规划Stage 5 要求先运行不带--write的确定性引擎记录版本化 JSON 报告、变更路径、结构化诊断与退出码。app-cold-strong 中实际执行的 dry-run 命令为pnpm exec rxjs-migrate \ --source-root . \ --source-repo fixture://app-cold-strong \ --source-sha f7cb6d139c979bf8f5b577120529ac236e59b9a4 \ --mode cold \ --framework preserve \ src/request.ts test/request.test-source.tsdry-run 结果2 个变更计划、0 个诊断、精确选中operator.map能力。这里有两个值得注意的设计--mode cold是强制显式的生命周期声明。CLI 源码packages/migrate/src/cli.ts只接受cold与platform两个取值二者不可推断、必须显式给出--source-repo/--source-sha提供来源溯源确保每次写入都带有可审计的出处patch.diff 中每个文件头都写入了// Migrated from fixture://app-cold-strong f7cb6d...注释。引擎 CLI 的完整参数来自 cli.ts 的参数解析与校验逻辑参数必填取值/行为test files...是至少一个源文件--source-root dir是源仓库根目录--source-repo url是来源仓库标识本场景为fixture://协议--source-sha sha是来源提交 SHA--mode cold\|platform否生命周期模式二者互斥--framework preserve\|mocha-chai-vitest否默认preserve保留原测试框架--write --out-dir dir否缺省为 dry-run--write必须搭配--out-dir值得注意的实现细节createMigrationCliReportcli.ts总是先以write: false规划全部文件只有当计划中没有refused结果时才执行写入——即写入仅在所有 dry-run 结果成功后才会尝试这是引擎内置的安全边界。退出码语义为0成功、1refused、2参数非法、3运行失败cli.ts。应用迁移补丁ColdObservable、符号 map 与 addTeardownStage 6 只应用已评审的 dry-run 计划。patch.diff展示了src/request.ts的完整转换这是理解 RxJS Next 冷语义的关键样本迁移前RxJS 7.8.1import { Observable, map } from rxjs; export function request(log: string[]): Observablenumber { return new Observablenumber((subscriber) { log.push(start); subscriber.next(21); return () log.push(stop); }).pipe(map((value) value * 2)); }迁移后RxJS 8.0.0-alpha.14// Migrated from fixture://app-cold-strong f7cb6d139c979bf8f5b577120529ac236e59b9a4 // Source: src/request.ts import { ColdObservable } from rxjs; import { map } from rxjs/map; export function request(log: string[]): Observablenumber { return new ColdObservablenumber((subscriber) { log.push(start); subscriber.next(21); subscriber.addTeardown(() log.push(stop)); })map value * 2); }这次重写对应四条 RxJS Next 关键语义new Observable→new ColdObservable显式声明每次直接订阅都创建独立生产者的生命周期.pipe(map(...))→mapRxJS Next 中操作符转为 Symbol 键import { map } from rxjs/map符号键操作符保持冷生命周期返回 teardown 函数 →subscriber.addTeardown(...)teardown 注册从构造函数返回值改为订阅器上的显式方法unsubscribe()语义 → AbortSignal 取消测试侧测试改用AbortController/AbortSignal驱动取消。从源码看packages/rxjs/src/cold-observable.tsColdObservable的关键实现是覆写subscribe()每次调用都新建一个ColdSubscriber持有独立AbortController并立即执行构造函数init(subscriber)从而保证一次直接订阅 一个独立生产者执行而原生字符串命名方法如map、filter则故意穿越回平台生命周期并返回平台 Observable只有 RxJS Symbol 键操作符使用共享构造协议返回ColdObservable。这正是迁移中[map]必须使用符号键的原因——用字符串map会把结果拉回平台共享语义。受保护测试的强化从 unsubscribe 到 AbortSignal测试文件test/request.test-source.ts同样被迁移三个受保护测试从订阅对象 unsubscribe()改写为AbortControllersignal配置项。patch.diff 中的记录显示变更类型为PT-COLD-INDEPENDENTstrengthened强化、PT-COLD-CANCELLATIONequivalent、PT-COLD-TEARDOWNequivalent。it(PT-COLD-INDEPENDENT starts one producer per direct subscription, () { const log: string[] []; const values: number[] []; const first new AbortController(); const second new AbortController(); request(log).subscribe((value) values.push(value), { signal: first.signal }); request(log).subscribe(null, { signal: second.signal }); expect(log).toEqual([start, start]); // 两次订阅 两个独立生产者 expect(values).toEqual([42]); // 21 经 map 映射为 42 first.abort(); second.abort(); }); it(PT-COLD-CANCELLATION closes the producer on unsubscribe, () { const log: string[] []; const controller new AbortController(); request(log).subscribe(null, { signal: controller.signal }); controller.abort(); expect(log).toEqual([start, stop]); // 取消关闭自己拥有的生产者 }); it(PT-COLD-TEARDOWN keeps teardown ordering observable, () { const log: string[] []; const producer new AbortController(); const outer new AbortController(); request(log).subscribe(null, { signal: producer.signal }); outer.signal.addEventListener(abort, () { producer.abort(); log.push(outer-stop); }); outer.abort(); expect(log).toEqual([start, stop, outer-stop]); // 生产者 stop 先于外层 outer-stop });这三个测试分别锚定契约中的三个行为主张并从ColdSubscriber的源码得到印证cold-observable.tsColdSubscriber通过AbortSignal.any([parentSignal, 内部AbortController.signal])融合外部信号与自身取消信号active由!signal.aborted判定addTeardown把 teardown 压入数组在 abort 时按注册顺序执行。这也解释了为何迁移后的取消路径是标准 Web 平台原语而非库私有的 Subscription 对象。发现并修复迁移缺陷teardown 顺序Stage 7 的铁律是不能为了绿灯而削弱测试。第一次迁移后的pnpm test确实失败了PT-COLD-TEARDOWN暴露的顺序是start, outer-stop, stop而期望是start, stop, outer-stop——生产者的 teardownstop没有先于外层订阅的 teardownouter-stop执行。command-results.md将其明确分类为迁移缺陷migration defect而不是产品缺口或环境问题。修复遵循小批量修复 重复相关门禁的规则且未改动受保护期望测试仍要求[start, stop, outer-stop]。修复后依次执行pnpm exec vitest --run -t PT-COLD-TEARDOWN # 聚焦测试1 passed2 filtered pnpm install --offline --ignore-workspace --frozen-lockfile # 冻结离线安装 pnpm run build # RxJS Next 下 TypeScript 通过 pnpm test # 1 个文件、3 个受保护测试全绿最后再次运行与 dry-run 完全相同的引擎命令做幂等性验证两个集成文件均unchanged诊断稳定为空——证明引擎不会反复改写已迁移的代码。离线依赖切换本地 tarball 与 pnpm overrides由于网络被禁用RxJS Next 依赖必须来自仓库本地授权的 tarball。patch.diff展示了package.json与pnpm-lock.yaml的完整切换方式// package.json 变更节选 dependencies: { rxjs/observable-polyfill: file:.qualification/packages/rxjs-observable-polyfill-8.0.0-alpha.14.tgz, rxjs: file:.qualification/packages/rxjs-8.0.0-alpha.14.tgz }, pnpm: { overrides: { rxjs/observable-polyfill: file:.qualification/packages/rxjs-observable-polyfill-8.0.0-alpha.14.tgz } }rxjs8.0.0-alpha.14的依赖也从tslib变更为rxjs/observable-polyfilllockfile 中rxjsfile:...tgz的 dependencies 由tslib: 2.8.1改为指向 polyfill tarball且tslib2.8.1条目被移除。polyfill 的overrides是为了钉住rxjs对rxjs/observable-polyfill的传递依赖也指向本地 tarball避免 pnpm 尝试访问不可用的注册表元数据。实际安装过程并非一帆风顺command-results.md第 6 阶段前三次组合式离线pnpm add均因 pnpm 尝试获取注册表元数据或报告意外 store 位置而以退出码 1 失败且没有任何依赖文件被改动。最终通过先单独安装 polyfill tarball、再在根级 local-tarball override 后单独安装 RxJS tarball的方式成功RxJS changed from 7.8.1 to local 8.0.0-alpha.14。随后pnpm install --offline --ignore-workspace --frozen-lockfile验证 lockfile 最新、离线状态有效。这一细节说明离线迁移中 tarball 的安装顺序与 override 配置同样属于验收证据的一部分。三个控制项资格认证的验收语义最终报告列出的Required controls是整个认证的验收标准三者全部satisfied控制项语义锚定证据control:cold-sharing-drift冷语义未漂移为平台共享PT-COLD-INDEPENDENT两次订阅产生两个start互不共享control:cancellation-ownership取消所有权正确PT-COLD-CANCELLATIONabort 只关闭自己拥有的生产者start, stopcontrol:teardown-order-driftteardown 顺序未漂移PT-COLD-TEARDOWNstart, stop, outer-stop在record.json的诊断部分这三个控制项均记录为resolvedgate 向量 10 项baseline-before-changes、protected-tests-intact、characterizations-before-migration、compilation、build、tests、contract-manifest、diagnostics-reviewed、no-weakened-tests、final-report全部passedheld-out 行为下一阶段对 RxJS Next 运行全部受保护测试同样通过。值得注意的是PT-COLD-INDEPENDENT的测试变更类型是strengthened——它不仅验证两个生产者还额外断言了映射值42属于强化而非削弱证据。清单校验与 readiness收尾交接Stage 8 要求用已安装 schema 校验契约清单并单独评估迁移就绪度schema 有效性与 readiness 是两个独立的检查。app-cold-strong 的收尾结果契约清单 schema 校验validreadinessreadyfindingCodes: []、unsupportedUnitIds: []、acceptedBlockers: []manifest 一致性implemented与declared均只有request-cold-producer / producer-per-direct-subscription完全一致工件完整conversation、contract-manifest、patch、command-results、final-report 五类工件全部捕获并记录 SHA-256 摘要附加审计git diff --check无空白错误所有受保护标记与必需控制项存在受保护 fixture 文件未改动。最终报告据此给出结论预期的completed结果由记录的基线、dry run、迁移行为、最终门禁与就绪度评估共同支持——这正是整个资格认证体系的验收逻辑不是单点绿灯而是从基线到收尾的完整证据链。从本次认证可迁移到生产迁移的方法论回顾 app-cold-strong 全过程可提炼出一套可复用的 RxJS 7 → RxJS Next 冷语义迁移检查单先定契约后动代码对每个生命周期敏感单元先记录行为主张、证据分类与目标生命周期cold/platform并取得开发者显式批准绝不凭语法或文件名推断共享语义基线必须绿在未改动项目上完成 build 与全部受保护测试网络禁用环境下更要记录环境事实Node/pnpm/框架版本引擎先 dry-runrxjs-migrate默认只规划不写入只有计划中无refused时才允许带--write --out-dir落地小批量 溯源每个文件保留来源注释fixture://与 SHA一个批次改完先做解析、窄类型边界与幂等性检查失败要分类迁移缺陷修复且不弱化证据、产品缺口保留失败证据上报、有意分叉须先记录新行为与用户影响三者严格区分离线依赖用 tarballfile:协议 pnpm overrides 钉住传递依赖--frozen-lockfile验证 lockfile控制项验收为冷语义、取消所有权、teardown 顺序各设一个受保护测试作为防回归的验收锚点。进一步阅读迁移技能完整规则packages/migrate/skill/SKILL.md契约清单与验证记录contract-manifest.json、record.json分阶段命令与退出码command-results.md实际迁移补丁patch.diff引擎 CLI 实现packages/migrate/src/cli.tsColdObservable/ColdSubscriber源码packages/rxjs/src/cold-observable.ts同批次其他场景platform-strong、library-mixed-strong、library-weak-unsupported可在 qualification-runs 目录下对比阅读。【免费下载链接】rxjsA reactive programming library for JavaScript项目地址: https://gitcode.com/gh_mirrors/rx/rxjs创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价