fix(loader): preserve virtual resource identity in Editor Preview - #3079
fix(loader): preserve virtual resource identity in Editor Preview#3079luzhuang wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. 🗂️ Base branches to auto review (1)
Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
对 feat/migrate-2.0...f83b1902167f244571fae82bb047c76ac8eb0654 的 5 个提交做了首次完整增量审查。把虚拟资源的逻辑身份与物理传输地址拆开,方向正确;但当前仍有 1 个 P1 会在 baseUrl 与 VFS 同时启用时绕过虚拟资源映射,另有 3 个 P2。实际 review 动作为 REQUEST_CHANGES,目标 HEAD 为 f83b1902167f244571fae82bb047c76ac8eb0654。自动 CR 不替代人工 Reviewer 的合入门禁,修复后仍需人工审核确认。
问题
-
[P1] 保留虚拟资源的逻辑
item.url,不要让baseUrl把它改写成第三种混合地址 —packages/core/src/asset/ResourceManager.ts:364-370先命中了virtualResourceEntry,随后仍无条件把相对assetBaseURL与baseUrl合并;而packages/loader/src/SpriteAtlasLoader.ts:28,36,58正依赖item.url作为 atlas 与页面的虚拟身份。触发方式是同时设置resourceManager.baseUrl并注册SpriteAtlas/Migrated/ui.atlas -> blob:...atlas及其页面映射:传给 loader 的item.url会变成https://base/.../SpriteAtlas/Migrated/ui.atlas,_request()和子页面load()都无法命中以SpriteAtlas/...为 key 的 VFS,最终错误请求 base URL。应保留ResourceManager为唯一解析 owner:命中virtualResourceEntry时让item.url始终保持assetBaseURL,仅把virtualResourceEntry.path写入resolvedUrl/cache key;只有未命中 VFS 的相对 URL 才应用baseUrl。同时把现有仅断言 loader type 的 baseUrl 用例改成真实 atlas 链路测试,断言 atlas 配置与页面最终都请求各自的物理地址。 -
[P2] 对 Stage-3 无法被 clone traversal 消费的字段显式拒绝,不要静默注册 —
packages/core/src/clone/CloneManager.ts:14-37的 context 接受string | symbol,且没有检查 Stage-3 context 的private/static;下游CloneUtil._deepCloneObject与ComponentCloner.cloneComponent却只用Object.keys(source)。因此@deepClone/@assignmentClone用在 private、static 或 symbol-named field 时 TypeScript 可以进入这条新协议,但 mode 永远不会被消费,显式 clone intent 静默退化。最小方向是把这些 unsupported context 在 decorator 边界明确报错,并补负向契约测试;若确实要支持 symbol field,则只扩展 enumerable own-symbol traversal,仍应明确拒绝 private/static,不能增加 fallback 或第二条 clone 路径。 -
[P2] 修正本次新增注释中的协议事实与格式 —
packages/core/src/clone/CloneManager.ts:9写成 Stage-3 field decorator 接收“initial value”,实际第一参数是undefined,初始字段值只会传给 decorator 返回的 initializer;packages/core/src/asset/LoadItem.ts:16-18又宣称resolvedUrl可用于解析相对文件,但SpriteAtlasLoader.ts:24-28已正确说明 Blob 等物理 URL 不能作为兄弟资源基址。请把契约统一为:url是相对依赖的逻辑基址,resolvedUrl仅是 ResourceManager 派生的物理传输/格式判定地址。此外CloneManager.ts:30-32、ShaderLoader.ts:14-15、SpriteAtlasLoader.ts:24-27、Utils.ts:85-88的新增//注释块末尾句号应按仓库注释规范移除。 -
[P2] 让 PR 元信息覆盖独立的 clone 协议变更 — 标题与 Summary 只描述 virtual resource identity,但首个提交同时改变了三个公开 clone decorator 的调用协议和运行时存储时机。这与 loader 修复是可独立理解、回滚的变更单元。优先拆分;若迁移预览分支必须合并交付,至少在标题/Summary、行为变化与验证中明确列出 Stage-3 decorator 支持及其边界,避免 release/changelog 和回滚决策漏掉这项公开 API 行为。
架构、熵增与测试治理
上游 Editor Builder/project manifest 分别拥有 virtualPath(逻辑身份)和 path(物理产物);Engine 内应由 ResourceManager 唯一拥有映射与 cache key,loader 只消费规范化结果;下游 ShaderLoader 用物理后缀选择 .shaderc 协议,SpriteAtlasLoader 用逻辑路径派生兄弟资源。改动新增 resolvedUrl 后,本应从一个含混 URL 收敛成两项正交事实,但保留的 baseUrl 改写让 item.url 仍在“逻辑身份/普通物理 URL”间切换,形成第三种混合语义;删除虚拟路径上的这次改写后,数据流可收敛为 manifest -> ResourceManager -> { logical url, physical resolvedUrl } -> loader,无需同步层或 legacy fallback。
Clone 链上,legacy decorator 与 Stage-3 decorator 是真实编译协议边界,两者复用 _registerFieldMode 和同一 clone traversal,没有新增平行 clone 状态机;需要删除的是对不可消费 context 的静默路径。现有测试没有为了旧契约保留生产 compatibility branch,也没有应删除的 legacy fixture;但 SpriteAtlas 测试直接调用 loader,绕过了本次最关键的 ResourceManager 规范化边界,Stage-3 测试也只覆盖 string-named instance field。应按上述公开链路与负向边界补测,不要用 mock/兼容分支继续掩盖 owner 漂移。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
对 f83b1902167f244571fae82bb047c76ac8eb0654...865fa27c9976a90479a4a62eeb8bf0cfda9c503d 的 1 个增量提交做了复审,并按当前 fix/migrate-stage3-clone-decorators...865fa27c9976a90479a4a62eeb8bf0cfda9c503d 重新核对了完整 loader diff。上一轮 baseUrl + VFS 的 P1 已修复;但本轮沿 Shader 下游继续追踪后发现 1 个新的 P1:源码 Shader 的逻辑路径仍被物理 Blob URL 覆盖,导致相对 #include 解析失败;另有 1 个上轮未闭环的注释 P2。当前阻塞级别为 P1,实际 review 动作为 REQUEST_CHANGES,目标 HEAD 为 865fa27c9976a90479a4a62eeb8bf0cfda9c503d。自动 CR 不替代人工 Reviewer 的合入门禁,修复后仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由865fa27c9976a90479a4a62eeb8bf0cfda9c503d修复:ResourceManager命中 VFS 时保留item.url = assetBaseURL,只把物理地址写入resolvedUrl/cache key;新的 SpriteAtlas 用例也从ResourceManager.load()贯通验证了 atlas 与页面各自命中物理地址。- Stage-3 decorator 对不可消费 context 静默注册 — 当前 PR 已改为依赖 #3078,base 是
fix/migrate-stage3-clone-decorators;clone 文件不再属于本 PR 的实际 diff,因此该项对 #3079 不适用,需在依赖 PR 独立闭环。 LoadItem对逻辑/物理 URL 的协议说明失真 — 已修复:url明确承载虚拟资源身份,resolvedUrl明确只用于直接传输与格式判定、不能作为虚拟兄弟资源基址。- PR 元信息遗漏独立 clone 协议变更 — 已通过依赖 #3078、调整 base,并在 PR body 中单列 Dependency/Contract/Change/Verification 收口;当前标题与实际 loader diff 一致。
问题
- [P1] Shader 只应用物理 URL 判型,请求和相对
#include基址必须继续使用逻辑 URL —packages/loader/src/ShaderLoader.ts:16-28把item.resolvedUrl赋给同一个url,随后既传给ResourceManager._request(),又传给Shader.create(..., path)。触发方式是注册源码 ShaderShader/Migrated/source.shader -> blob:https://.../source,且源码包含#include "./common.glsl":Shader.create的公开契约明确第三参数用于解析相对 include(packages/core/src/shader/Shader.ts:49,97),下游packages/shader-compiler/src/Preprocessor.ts:35-40会执行new URL(includeName, basePathForIncludeKey);Blob URL 不能作为相对 URL 基址,这里会抛TypeError: Invalid URL,Editor Preview 中该 Shader 无法编译。同时,_request(resolvedUrl)会让已经解析好的物理地址再次经过_getRemoteUrl,当物理地址恰好也是另一个 VFS key 时会发生二次映射。应保留ResourceManager为唯一映射 owner:分别取logicalUrl = item.url!与transportUrl = item.resolvedUrl ?? logicalUrl,只用transportUrl判断.shaderc,两条请求都调用_request(logicalUrl, ...),源码分支把logicalUrl传给Shader.create。对应地,重写tests/src/loader/ShaderLoader.test.ts:16-28:不要直接构造LoadItem调内部 loader 并断言物理地址进入_request;从resourceManager.load(virtualPath)走完整 VFS 链,断言_requestByRemoteUrl收到物理地址,并补一个 Blob 物理地址 + 相对 include 的源码 Shader 用例。无需增加 compatibility branch 或第二条解析路径。 - [P2] 清理本轮仍未闭环的新增
//注释句号 —packages/core/src/Utils.ts:85-88、packages/core/src/asset/ResourceManager.ts:364-366、packages/loader/src/ShaderLoader.ts:14-15、packages/loader/src/SpriteAtlasLoader.ts:24-27的新增注释块仍以句号结尾;tests/src/loader/ShaderLoader.test.ts:22与tests/src/loader/SpriteAtlasLoader.test.ts:34的@ts-ignore说明也同样如此。按仓库规范,单行/连续//注释末尾不加句号;统一移除即可。LoadItem的多行 TSDoc 句号应保留。
架构、熵增与测试治理
上游 Editor manifest 仍是 { virtualPath, path } 的事实 owner,Engine 内 ResourceManager 应唯一拥有 VFS 映射、cache key 和 { logical url, transport resolvedUrl } 的机械派生;下游 SpriteAtlas 已正确使用逻辑 URL 派生页面、由 _request/load 回到 ResourceManager 映射,Texture 也沿用同一入口。新增一个不持久化的 resolvedUrl 派生值本身把原先含混的单 URL 拆成两个正交概念,没有形成第三份真相;但 Shader 当前又把两者合回同一局部变量,并让物理地址重入逻辑映射,实际新增了第二条转换路径。保留 ResourceManager owner、删除 Shader 的物理地址重映射并恢复逻辑 include 基址后,数据流才能收敛为 manifest -> ResourceManager -> { logical, transport } -> loader。
测试侧,新的 SpriteAtlas 用例已经替换了绕过规范化边界的内部直调用,能够反向守住上一轮 P1;Shader 用例却仍直接调用 loader,并把“物理地址进入 _request”固化成断言,属于按新公开契约应重写的失效 fixture。应删除这条错误断言并改走公开加载链,而不是为了它保留 wrapper、fallback、镜像状态或第二条 URL 转换。除 Shader 这条路径外,本轮未发现新增兼容分支、平行状态机或可删除的持久镜像状态。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
对 865fa27c9976a90479a4a62eeb8bf0cfda9c503d...18edc9f85baeaaebce1985445b7fa09a71d20600 的 1 个增量提交做了复审,并按当前 fix/migrate-stage3-clone-decorators...18edc9f85baeaaebce1985445b7fa09a71d20600 重新核对了完整 loader diff。上一轮 Shader 请求与 include 基址混用物理 URL 的 P1 已修复;但替代实现重新用物理地址后缀决定 Shader 编码,和已合入 dev/2.0 的 #3074 契约冲突,opaque CDN/hash 地址下的预编译 Shader 仍会走错解析器;另有 2 个 P2。当前阻塞级别为 P1,实际 review 动作为 REQUEST_CHANGES,目标 HEAD 为 18edc9f85baeaaebce1985445b7fa09a71d20600。自动 CR 不替代人工 Reviewer 的合入门禁,修复后仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由865fa27c9976a90479a4a62eeb8bf0cfda9c503d修复:VFS 命中时保留item.url = assetBaseURL,cache key 与实际请求仍使用映射后的path。- Stage-3 decorator 对不可消费 context 静默注册 — #3079 已改为依赖 #3078,clone 文件不在当前实际 diff 中;该项对本 PR 不适用。
LoadItem的逻辑/物理 URL 契约失真及派生状态泄漏 — 已由18edc9f85baeaaebce1985445b7fa09a71d20600修复:resolvedUrl从公开类型、ResourceManager 写入和测试 fixture 中全部删除,物理地址只保留在虚拟资源表与请求边界。- PR 元信息遗漏独立 clone 协议变更 — 已通过依赖 #3078、调整 base,并重写 PR body 的 Dependency/Contract/Change/Verification 收口。
- Shader 把物理 URL 用作请求输入与相对
#include基址 — 已由18edc9f85baeaaebce1985445b7fa09a71d20600修复:两条请求都使用逻辑url,源码分支也把逻辑url传给Shader.create;新测试从ResourceManager.load()贯通验证了物理请求地址和逻辑 include 基址。
问题
- [P1] 不要再从物理 URL 后缀推断 Shader 编码,编码事实应由已取回的 payload 决定 —
packages/loader/src/ShaderLoader.ts:15-20额外读取_getRemoteUrl(url)并用/\.shaderc.../选择 JSON/Text 分支。当前 Preview 的 Blob upload 会附加#name,但这只是一个上游实现细节;Builder 的 CDN upload 直接保留服务端 URL,公开{ virtualPath, path }契约也允许 opaque/hash 地址。触发方式是Shaders/custom.shader -> https://cdn.example.com/assets/8fca12?version=1,内容为预编译 JSON:正则返回 false,代码把 JSON 字符串交给Shader.create的 ShaderLab 源码解析器,资源加载失败。这个场景已经由合入dev/2.0的 #3074(8fe06577d36f92a226b1031e7613f925aaac72e4,fix(loader): decouple shader format from physical path)明确修复并用 opaque physical path 反向验证;当前分支是在恢复其根因。应保留ResourceManager为唯一virtualPath -> path映射 owner,删除remoteUrl、私有_getRemoteUrl访问、后缀正则和 JSON/Text 双请求分支,直接采用 #3074 的单次 text 请求 + payload 判型:JSON payload 交给_createFromPrecompiled,其余源码交给Shader.create(code, undefined, logicalUrl)。同时把tests/src/loader/ShaderLoader.test.ts:16-40的#outline.shadercfixture 改成无扩展 opaque 地址并返回 JSON 文本;不要再用带后缀 fixture 固化已退场的 transport 命名契约。 - [P2] 统一 Texture 首次解码与设备恢复的 Image 失败路径 —
packages/loader/src/TextureLoader.ts:103-105已把初次图片解码失败改为包含逻辑 URL 与字节数的Error,但同一数据流下游TextureContentRestorer.restoreContent()的平行 Image 解码仍在:154-165直接 reject 原始Event。资源在首次加载后、设备恢复前若 CDN 内容变化或映射产物损坏,诊断信息仍会丢失;同一个字节到 Image 的转换也继续维护两套Blob/Image/onload/onerror/revokeObjectURL状态机。应保留逻辑url和buffer.byteLength为唯一诊断事实,提取一个被初次加载与 restorer 共用的 Image 解码 helper,删除两份事件/URL 生命周期处理,并补失败回归测试;不要再加 wrapper 或兼容分支。 - [P2] 清理仍未闭环的新增
//注释句号 —packages/core/src/Utils.ts:85-88、packages/core/src/asset/ResourceManager.ts:364-366、packages/loader/src/SpriteAtlasLoader.ts:24-27,以及tests/src/loader/SpriteAtlasLoader.test.ts:39,43的新增连续///@ts-ignore注释仍以句号结尾。按仓库规范统一移除;LoadItem的多行 TSDoc 句号应保留。ShaderLoader的对应注释应随问题 1 的错误判型路径一起删除,而不是继续润色。
架构、熵增与测试治理
上游 Editor manifest 是 { virtualPath, path, type } 的事实 owner:virtualPath 负责稳定身份,path 只负责传输,Preview 为 Blob URL 附加文件名并不是协议;Engine 内 ResourceManager 应唯一拥有映射、cache/loading key 与请求边界。删除 resolvedUrl 后,loader 输入从“逻辑 URL + 派生物理 URL”两项收敛回一个逻辑身份,没有新增持久镜像状态,SpriteAtlas 页面也已经沿 logical atlas -> logical page -> ResourceManager -> physical request 正确闭环。
当前剩余熵增集中在两个落点:Shader 又新增一次私有映射查询、一个 transport 后缀正则和 JSON/Text 两条请求/解析路径,把 payload 编码事实错误转移给地址命名;应保留 payload 为编码 owner,并删除这整条后缀判型路径。Texture 则让同一 Image 转换继续存在两套错误与对象 URL 生命周期 owner;应合并为单一 helper。测试侧,新的 Shader/Atlas 用例已经改走公开 ResourceManager.load() 链路,这是正确方向;但 Shader 的带 .shaderc fragment fixture 锁定了错误的 transport 契约,必须按 #3074 的 opaque path + JSON payload 公开契约重写。除上述两处外,未发现新增 compatibility branch、legacy fallback、平行加载状态机或为旧测试保留的生产 wrapper。
|
已在
PR 描述和仓库内工程记录已同步更新,请基于当前 head 重新 review。 |
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
对 18edc9f85baeaaebce1985445b7fa09a71d20600...bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 的 1 个增量提交做了复审,并按当前 fix/migrate-stage3-clone-decorators...bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80 重新核对了完整 loader diff。Shader 已恢复 #3074 的 payload 判型契约,Texture 两套 Image 解码状态机也已收敛;本轮未发现新的 P0/P1,但上一轮注释规范 P2 尚未完全闭环。当前阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由865fa27c9976a90479a4a62eeb8bf0cfda9c503d修复:VFS 命中时保留逻辑item.url,cache/loading key 与实际请求继续使用映射后的物理path。- Stage-3 decorator 对不可消费 context 静默注册 — #3079 已依赖 #3078 并把 base 指向
fix/migrate-stage3-clone-decorators,clone 改动不在当前实际 diff 中,因此对本 PR 不适用。 LoadItem泄漏派生物理 URL 与双源状态 — 已由18edc9f85baeaaebce1985445b7fa09a71d20600修复:resolvedUrl已从公开类型、ResourceManager 写入与测试 fixture 中删除。- PR 元信息遗漏独立 clone 协议变更 — 已通过依赖 #3078、调整 base,并在 PR body 中明确 Dependency、Contract、Change 与 Verification 收口。
- Shader 把物理 URL 用作请求输入与相对
#include基址 — 已由18edc9f85baeaaebce1985445b7fa09a71d20600修复:请求使用逻辑 URL,源码编译也保留逻辑路径作为 include 基址。 - Shader 从物理 URL 后缀推断编码 — 已由
bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80修复:删除_getRemoteUrl、后缀正则与 JSON/Text 双请求,恢复单次 text 请求后按 payload 判型;opaque CDN 回归用例可反向守住该契约。 - Texture 首次解码与设备恢复维护平行 Image 状态机 — 已由
bc9a989d88742a1e1a4f1f1216e9f0d53a65cd80修复:两条路径共用decodeImage,对象 URL 生命周期与包含逻辑 URL、字节数的诊断错误由同一 helper 统一拥有;恢复失败测试可证伪旧的原始Event路径。
问题
- [P2] 清理仍未闭环的新增
//注释句号 —packages/core/src/Utils.ts:85-88、packages/core/src/asset/ResourceManager.ts:364-366、packages/loader/src/SpriteAtlasLoader.ts:24-27,以及tests/src/loader/SpriteAtlasLoader.test.ts:39,43的新增连续///@ts-ignore注释仍以句号结尾。上一轮指出的 Shader 注释已随错误判型路径删除,但这些落点没有变化;按仓库规范统一移除末尾句号即可。LoadItem的多行 TSDoc 句号应保留。
架构、熵增与测试治理
沿本次直接链路复核后,上游 Editor manifest 继续拥有 { virtualPath, path, type } 的输入事实,Engine 内 ResourceManager 是 virtualPath -> path 映射、cache/loading key 与 I/O 请求边界的唯一 owner;下游 SpriteAtlas 只从逻辑路径派生页面,Shader payload 是源码/预编译表示的 owner,Texture 的 decodeImage 是 Image 事件和对象 URL 生命周期的 owner。相较上一 head,Shader 删除了 1 次私有映射查询、1 个 transport 后缀判型和 JSON/Text 两条请求路径;Texture 将 2 套解码状态机合并为 1 套,没有新增持久状态、同步层或第三份真相。
测试侧,Shader 的 fixture 已从带 .shaderc 后缀的物理地址改为 opaque CDN URL,并从公开 ResourceManager.load() 链路验证物理请求、payload 解析与逻辑 include 基址;Texture 恢复失败用例会在旧实现返回原始浏览器 Event 时失败。未发现为旧测试保留的 compatibility branch、legacy fallback、wrapper、镜像状态或第二条转换/校验路径,也没有需要随新契约删除的残留 fixture、mock 或 snapshot。
51dffa3 to
2b82411
Compare
bc9a989 to
3719142
Compare
3719142 to
6291edd
Compare
|
已解耦并直接重建到最新
本地验证:聚焦 5 files / 28 tests;全量 137 files / 1758 tests; |
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
上一轮 checkpoint bc9a989 之后分支已重建,旧、新 head 历史发散;本轮因此以实际 PR 范围 f6da19d...6291edd 的单个提交、8 个文件做了完整增量复审,并重新核对当前 tree 的 loader 上下游。重建已移除 clone 与重复 Shader diff,VFS 逻辑身份、相对路径和 Texture 解码 owner 均已收敛;本轮未发现新的 P0/P1/P2。当前阻塞级别为 无,实际 review 动作为 COMMENTED,目标 HEAD 为 6291edd。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
- baseUrl 覆盖虚拟资源逻辑身份 — 已在当前 6291edd 闭环:VFS 命中时 LoadItem.url 保留 virtualPath,cache/loading key 与 I/O 请求继续由 ResourceManager 从表中机械映射到物理 path;Atlas 链路测试贯通验证了 atlas 与 page 各自命中物理地址。
- Stage-3 decorator 对不可消费 context 静默注册 — 当前 head 直接建立在 feat/migrate-2.0@f6da19d79673cfe8f8a5ffa739a82a7ebdeb4619,不再依赖 #3078,单提交及完整 diff 均无 clone 改动,因此对本 PR 不适用。
- LoadItem.resolvedUrl 泄漏派生物理地址并形成双源 — 当前公开类型、ResourceManager 写入及测试 fixture 均无该字段;物理地址只保留在虚拟资源表以及 cache/I/O 边界。
- PR 元信息遗漏独立 clone 协议变更 — 重建后 clone 已完全移出实际 diff,标题、正文、单提交和 8 文件变更范围现已一致。
- Shader 把物理 URL 用作请求输入与相对 #include 基址 — 最新基线已包含 #3074;当前 ShaderLoader 仍以逻辑 URL 请求并传给 Shader.create 作为 include 基址,本 PR 未复制旧 Shader production/test 改动。
- Shader 从物理 URL 后缀推断编码 — 最新基线继续采用单次 text 请求后按 payload 判型;opaque 物理地址契约由基线测试拥有,当前 PR 没有恢复后缀正则、JSON/Text 双请求或私有映射查询。
- Texture 首次解码与设备恢复维护平行 Image 状态机 — 当前 decodeImage 同时服务初次加载与 restoration,统一拥有 Image 事件、object URL 释放和包含逻辑资源身份与字节数的错误;恢复失败测试可反向证伪旧的原始浏览器 Event 路径。
- 新增单行注释末尾句号未清理 — 当前 Utils、ResourceManager 与 Atlas 测试新增的连续 // / @ts-ignore 注释均已按规范移除末尾句号;LoadItem 的多行 TSDoc 正确保留句号。
架构、熵增与测试治理
沿实际改动向上游一层核对,Editor project manifest / ProjectLoader 拥有 { virtualPath, path, type } 输入事实,ResourceManager 是 virtualPath -> path 映射、loader 选择、cache/loading key 与 I/O 请求边界的唯一 owner;Utils.resolveAbsoluteUrl 只机械派生逻辑依赖路径,不持有映射状态。向下游一层,SpriteAtlas 从逻辑 atlas 路径派生 page,再回到 ResourceManager 映射;Shader 由 payload 拥有表示格式、逻辑 URL 拥有 include 基址;Texture 的 decodeImage 拥有浏览器 Image/object-URL 生命周期。
相较基线,owner 数量没有增加:ResourceManager 只收紧 1 个 VFS/baseUrl 分支,路径解析仍是 1 条标准 URL 转换,Texture 的 2 套 Image 状态机合并为 1 套;没有新增持久状态、镜像字段、同步层、wrapper、legacy fallback、兼容分支或第三份真相。测试侧,Atlas 用例从公开 ResourceManager.load() 贯通逻辑身份、相对派生与两个物理请求边界;Texture restoration 用例守住统一错误契约;基线已拥有的 Shader 契约没有在本 PR 重复 fixture/mock。未发现为旧测试保留第二条生产转换/校验路径,也没有应随当前契约继续删除或重写的残留测试、fixture 或 snapshot。
分支关系
本 PR 已直接重建在最新
feat/migrate-2.0@f6da19d79,不再依赖 #3078,也不包含任何 clone 改动。最新基线已经包含 #3074 的 Shader payload 判型:一次 text 请求后由 payload 决定预编译 JSON 或 ShaderLab 源码,并以逻辑路径作为相对
#include基准。因此本 PR 不再重复修改 ShaderLoader,也不复制 Shader fixture。为什么要改
Editor Preview 中一个资源有两个正交事实:
virtualPath是稳定逻辑身份,用于引用、报错定位和推导同目录依赖path是 Blob/CDN/构建产物等物理传输地址,只负责实际读取字节此前
ResourceManager.baseUrl会把已经命中 VFS 的逻辑路径改写成普通 HTTP 地址。SpriteAtlas 再根据该地址推导页面路径时无法命中 VFS。相对逻辑路径还通过file://<path>计算,URL parser 把首段当成 hostname 并小写,导致SpriteAtlas/...变成不同的spriteatlas/...key。初版方案曾公开增加
LoadItem.resolvedUrl。全链路审查后已删除:物理地址已经由虚拟资源表与 ResourceManager 拥有,不应再复制到 Loader 输入形成第二份状态。修复后的契约
LoadItem.url中始终保留逻辑virtualPathbaseUrl只解析未命中 VFS 的普通相对 URLResourceManager唯一拥有virtualPath -> path映射、cache/loading key 与 I/O 请求边界file:///下按 path segment 解析,保留大小写与 leading-root 语义item.url推导页面;不增加 loader-specific transport 分支实际链路
例如 Atlas 内容中的
./auto-atlas_image_0.tex会先由逻辑 Atlas 路径推导出SpriteAtlas/Art/UI/auto-atlas_image_0.tex,再查 VFS 映射到对应 Blob/CDN URL;不会从 Blob URL 猜目录。实际改动
Utils.resolveAbsoluteUrl修复相对路径首段被 hostname 规则小写的问题LoadItem.url文档明确逻辑身份契约;没有新增resolvedUrl字段TDD 与验证
baseUrl覆盖逻辑身份、Texture restoration 仅返回原始浏览器 Eventpnpm run b:module:通过pnpm run b:types:15 个 package project 全部通过pnpm lint:0 error;仓库既有 1978 warnings 保持不变发布边界
0.0.0-experimental-2.0-migrate.5已从更早的分支状态发布,不包含本次重基后的独立 loader 提交;包含该修复的发布必须使用新版本。