fix(loader): preserve virtual resource identity in Editor Preview - #3084
fix(loader): preserve virtual resource identity in Editor Preview#3084luzhuang wants to merge 11 commits into
Conversation
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
WalkthroughVirtual resource loading now preserves logical paths while resolving physical transport URLs. URL handling covers leading slashes, and texture decoding shares cleanup and error reporting across initial loads and content restoration, with expanded atlas and texture tests. ChangesVirtual Resource Loading
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant ResourceManager
participant RemoteRequest
participant TextureLoader
ResourceManager->>ResourceManager: Preserve virtual resource URL
ResourceManager->>RemoteRequest: Request physical resource URL
RemoteRequest-->>TextureLoader: Return image bytes
TextureLoader->>TextureLoader: Decode image and revoke object URL
TextureLoader-->>ResourceManager: Return or restore Texture2D
Possibly related PRs
Suggested labels: Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ 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 |
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## dev/2.0 #3084 +/- ##
===========================================
+ Coverage 85.42% 85.57% +0.15%
===========================================
Files 811 811
Lines 94654 94703 +49
Branches 11512 11566 +54
===========================================
+ Hits 80854 81043 +189
+ Misses 13710 13568 -142
- Partials 90 92 +2
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮审查了 bd34daa45612af8b402cd3be916ff181f21ae742...53bb5b4542b6baa51d84247fde54878ddb78eedf 的 4 个提交、8 个文件,并把 348ebfa6e486648036c25d7db101b8ed0f045c70...53bb5b4542b6baa51d84247fde54878ddb78eedf 的三个注释增量、#3079 最终 tree 与当前 dev/2.0 上下游逐项对账。VFS 逻辑身份、Atlas 相对依赖和 Texture 解码 owner 的主体方向正确;当前未发现新的 P0/P1,但 dev/2.0 的公开缓存/取消入口仍保留一处同根因的双口径 P2。当前阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 53bb5b4542b6baa51d84247fde54878ddb78eedf。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已在348ebfa6e486648036c25d7db101b8ed0f045c70闭环:VFS 命中时LoadItem.url保留virtualPath,Atlas 链路测试贯通验证 atlas 与 page 各自命中物理地址。LoadItem.resolvedUrl泄漏派生物理地址并形成双源 — 当前公开类型、ResourceManager 写入及 fixture 均无该字段;物理地址只存在于虚拟资源表和内部 cache/loading/I/O 边界。- Shader 使用物理 URL 作为请求、相对
#include基址或编码判据 — 当前dev/2.0基线继续以逻辑 URL 请求和解析 include,并按 payload 区分源码/预编译表示;本 PR 没有恢复旧的后缀判型或双请求路径。 - Texture 首次解码与内容恢复维护平行 Image 状态机 — 当前两条路径共用
decodeImage,Image 事件、object URL 释放及包含逻辑资源身份和字节数的错误均由同一 helper 拥有;恢复失败测试可反向证伪旧路径。 - 迁移分支夹带 clone 协议及重复 Shader 变更 — #3084 直接基于
dev/2.0,完整 diff 仅含 loader/VFS 修复的 8 个文件,标题、正文和实际变更范围一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656与53bb5b4542b6baa51d84247fde54878ddb78eedf已统一连续///@ts-ignore说明并移除末尾句号;LoadItem的多行 TSDoc 正确保留句号。
问题
- [P2] 让公开缓存查询与取消操作复用 ResourceManager 的虚拟路径映射,删除逻辑/物理 key 双口径 —
packages/core/src/asset/ResourceManager.ts:346-359,421-431现在把虚拟资源按virtualResourceEntry.path写入_assetUrlPool/_loadingPromises,但:106-108的getFromCache(url)和:153-164的cancelNotLoaded(url)仍直接拿调用方 URL 索引这两个物理-key pool。注册Texture/page.tex -> blob:...后,await load("Texture/page.tex")再调用getFromCache("Texture/page.tex")会得到null;加载过程中调用cancelNotLoaded("Texture/page.tex")也找不到对应 promise。它们既违反本 PR 新明确的“请求 URL 是资源身份”契约,也让同一个 ResourceManager 对load与公开管理 API 维护两套 key 语义。应保留_virtualPathResourceMap为唯一映射 owner,把 load/cache/cancel 的 pool-key 派生收口到同一规则,并删除getFromCache/cancelNotLoaded对调用方 URL 的直接索引;不要通过同时写入 virtual/physical 两份镜像 key 来同步。补两条公开链路测试:虚拟资源加载后可按virtualPath取回同一对象,以及 pending 虚拟加载可按virtualPath取消。#3079 最终 tree 已有前一条缓存映射测试,可直接按当前公开契约重放。
架构、熵增与测试治理
向上游一层,Editor manifest / ProjectLoader 拥有 { virtualPath, path, type } 输入事实;ResourceManager 应唯一拥有 virtualPath -> path 映射、loader 选择、cache/loading key 与 I/O 边界,Utils.resolveAbsoluteUrl 只机械派生逻辑依赖路径。向下游一层,SpriteAtlas 从逻辑 atlas 路径派生 page,再回到 ResourceManager 映射;Shader payload 拥有表示格式、逻辑 URL 拥有 include 基址;Texture 的 decodeImage 拥有浏览器 Image/object-URL 生命周期。
相较基线,本 PR 没有新增持久状态、镜像字段、wrapper、legacy fallback 或 compatibility branch:LoadItem 没有引入第二个 resolved URL,Texture 的两套解码状态机反而合并为一套,三个后续提交也只有注释变化。剩余熵增是问题 1 中同一事实的两种公开 key 口径;应保留 ResourceManager 的映射与物理 pool 为 owner,删除公开入口的直接索引,而不是增加第三份 alias 状态。测试侧,Atlas 已从公开 ResourceManager.load() 贯通逻辑身份、相对派生和两个物理请求边界,Texture restoration 守住统一错误契约;当前缺口仅是 cache/cancel 管理链路。未发现为旧测试保留的生产兼容逻辑,也没有应随新契约继续保留的 legacy fixture、mock 或 snapshot。
|
@GuoLei1990 这条 P2 成立,已在 ccf00ca14 闭环。
验证结果:本地全量 124 files / 1658 tests,相关 4 files / 28 tests, |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
tests/src/core/resource/ResourceManager.test.ts (1)
184-204: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick winClean up the pending load created by this test.
new AssetPromise(() => {})never settles, and the test only restores the loader spy. Because the sameResourceManageris reused across tests, its_loadingPromisesretains this entry indefinitely. Cancel it infinally(usingphysicalPath) or use a self-cleaning resolved mock.Proposed fix
} finally { + resourceManager.cancelNotLoaded(physicalPath); loaderSpy.mockRestore(); }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/src/core/resource/ResourceManager.test.ts` around lines 184 - 204, Clean up the unresolved load created in the “preserves the virtual resource identity for loaders” test: in the finally block, cancel the pending resource-manager load using physicalPath before restoring loaderSpy, or replace the mock with a self-cleaning resolved AssetPromise. Ensure _loadingPromises does not retain the test entry.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/core/src/asset/ResourceManager.ts`:
- Around line 159-161: Update the cancellation loop in ResourceManager to parse
each logical URL and construct the same physical-path-plus-query key used by
_loadSingleItem before looking up _loadingPromises. Preserve direct URL
cancellation while ensuring virtual sub-assets such as material queries resolve
to their exact pending promise key, and add a regression test covering
cancellation of a virtual sub-asset.
---
Outside diff comments:
In `@tests/src/core/resource/ResourceManager.test.ts`:
- Around line 184-204: Clean up the unresolved load created in the “preserves
the virtual resource identity for loaders” test: in the finally block, cancel
the pending resource-manager load using physicalPath before restoring loaderSpy,
or replace the mock with a self-cleaning resolved AssetPromise. Ensure
_loadingPromises does not retain the test entry.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: fe5f665a-1713-4c56-a236-312193947492
📒 Files selected for processing (2)
packages/core/src/asset/ResourceManager.tstests/src/core/resource/ResourceManager.test.ts
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮完整增量审查了 53bb5b4542b6baa51d84247fde54878ddb78eedf...ccf00ca14d5da98cd2f0522c8fe52f67cceb9810 的 1 个提交、2 个文件,并沿 load/getFromCache/cancelNotLoaded 的 key 派生向上游 VFS 注册事实、向下游子资源 promise 与 loader I/O 各追一层。ccf00ca14 已闭环主资源按 virtualPath 查询缓存和取消加载的上一轮 P2,且没有引入逻辑/物理 alias;但带 ?q= 的虚拟子资源仍使用另一套 loading key 派生,当前有 1 个 P2。阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 ccf00ca14d5da98cd2f0522c8fe52f67cceb9810。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由348ebfa6e486648036c25d7db101b8ed0f045c70修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。LoadItem.resolvedUrl形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。- Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
- Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用
decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。 - 迁移分支夹带 clone/Shader 变更 — #3084 基于
dev/2.0,完整 PR diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656、53bb5b4542b6baa51d84247fde54878ddb78eedf已闭环单行注释、@ts-ignore说明和多行 TSDoc 标点;本增量新增/修改注释也符合该约定。 - 主资源 cache/cancel 的逻辑/物理 key 双口径 —
ccf00ca14已让getFromCache(virtualPath)、cancelNotLoaded(virtualPath)、_onSubAssetSuccess与_loadSingleItem复用_getRemoteUrl;新增两条公开链路测试能在旧实现上失败,且_assetUrlPool/_loadingPromises仍只存物理 key。
问题
- [P2] 让虚拟子资源取消复用
_loadSingleItem的完整 loading-key 派生,删除 query key 的第二套口径 —packages/core/src/asset/ResourceManager.ts:159-162现在把调用方传入的完整字符串直接交给_getRemoteUrl,但该 helper 在:187-189只对完整 key 做 VFS 精确查表;与此同时,:341-373,376-407,479的加载路径会先从Assets/model?q=materials[0]拆出基础 virtualPath,再映射为物理地址,并把子 promise 写到blob:...?q=materials[0]。因此cancelNotLoaded("Assets/model?q=materials[0]")仍会索引逻辑 key,返回的子资源 promise 不会被取消;新增测试tests/src/core/resource/ResourceManager.test.ts:206-229只覆盖无 query 的主资源,无法守住该分支。保留_parseURL为 query 拆分 owner、_virtualPathResourceMap为 virtualPath→physicalPath 事实 owner、物理_loadingPromises为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生收口为 load/cancel 共用的机械路径,并删除_loadSingleItem内联拼 key 与cancelNotLoaded直接精确映射这两套实现,不要增加 logical/physical 镜像 alias。补一条从公开load(virtualPath + "?q=...")到cancelNotLoaded的反向测试。本问题也与 CodeRabbit 的现有 discussion#discussion_r3672281364结论一致,本 review 不另发重复 inline comment。
架构、熵增与测试治理
向上游一层,Editor manifest / ProjectLoader 拥有 { virtualPath, path, type } 注册事实;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和 cache/loading key 派生。向下游一层,Loader 继续消费逻辑身份以解析相对依赖,_request 在叶子 I/O 边界映射物理地址;子资源链由 _parseURL / _parseQueryPath 生成规范 query,并以 _subAssetPromiseCallbacks 协调主/子资源完成状态。
相较上一 HEAD,本增量没有新增持久状态、镜像字段、wrapper、legacy fallback 或 compatibility branch;_getRemoteUrl 替换了 _onSubAssetSuccess 与 _loadSingleItem 的直接查表,owner 数量净减少,主资源公开入口也已统一。剩余熵增仅是完整 loading key 仍由 _loadSingleItem 拼装,而取消入口只做基础精确映射;按问题 1 收口后应只保留一条机械派生路径,不增加第三份真相。测试侧,新增 cache/main-cancel 用例均从公开 API 验证新契约,且新 pending 用例在 finally 清理自身 promise;未发现为了旧测试保留的生产 compatibility branch、legacy fallback、镜像状态或第二套校验。CodeRabbit 已单独跟踪旧 preserves the virtual resource identity for loaders fixture 的 pending promise 清理,本 review 不重复立项。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮完整增量审查了 ccf00ca14d5da98cd2f0522c8fe52f67cceb9810...8608990efae4bf89e0746e46818b6f66ffea179a 的 2 个提交、2 个文件,并回看完整 PR 的 8 个文件,沿公开 URL 契约与 load/getFromCache/cancelNotLoaded 的 key 派生向上游 VFS 注册事实、向下游子资源 promise 和 Loader I/O 各追一层。两个增量提交均只简化 TSDoc,没有改变执行逻辑或测试;主资源 cache/cancel 已闭环,但上一轮带 ?q= 的虚拟子资源取消仍未闭环,且本增量又抹去了 LoadItem.url 对逻辑身份的关键公开说明。本轮共 2 个 P2,未发现新的 P0/P1;目标 HEAD 的 12 项 GitHub checks 均通过。阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 8608990efae4bf89e0746e46818b6f66ffea179a。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由348ebfa6e486648036c25d7db101b8ed0f045c70修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。LoadItem.resolvedUrl形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。- Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
- Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用
decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。 - 迁移分支夹带 clone/Shader 变更 — #3084 基于
dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656、53bb5b4542b6baa51d84247fde54878ddb78eedf已闭环单行注释、@ts-ignore说明和多行 TSDoc 标点;本增量的 TSDoc 形式与标点也符合约定。 - 主资源 cache/cancel 的逻辑/物理 key 双口径 —
ccf00ca14d5da98cd2f0522c8fe52f67cceb9810已让getFromCache(virtualPath)、cancelNotLoaded(virtualPath)、_onSubAssetSuccess与_loadSingleItem复用_getRemoteUrl;公开链路测试能在旧实现上失败,且_assetUrlPool/_loadingPromises仍只存物理 key。
问题
-
[P2] 让虚拟子资源取消复用
_loadSingleItem的完整 loading-key 派生,删除 query key 的第二套口径 —packages/core/src/asset/ResourceManager.ts:159-162仍把调用方传入的完整字符串直接交给_getRemoteUrl,而该 helper 在:187-189只对完整 key 做 VFS 精确查表;加载路径却在:341-374,376-407,479先把Assets/model?q=materials[0]拆成基础 virtualPath,映射物理地址,再把子 promise 写到blob:...?q=materials[0]。因此cancelNotLoaded("Assets/model?q=materials[0]")仍索引逻辑 key,无法取消返回的子资源 promise;现有tests/src/core/resource/ResourceManager.test.ts:206-229只覆盖无 query 的主资源。最新两个提交只改 TSDoc,CodeRabbit discussion#discussion_r3672281364虽因邻近文档行被自动标记 resolved,代码行为并未改变。保留_parseURL为 query 拆分 owner、_getRemoteUrl/_virtualPathResourceMap为基础 virtualPath→physicalPath owner、物理_loadingPromises为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生从_loadSingleItem收口为 load/cancel 共用的机械路径,删除_loadSingleItem的内联拼 key和cancelNotLoaded的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开load(virtualPath + "?q=...")到cancelNotLoaded的反向测试。 -
[P2] 在
LoadItem.url上保留虚拟资源的逻辑身份契约,不要把本 PR 的关键边界简化成泛化的 “Resource URL” —packages/core/src/asset/LoadItem.ts:30-33将原来明确的“virtual resources keep their virtual path”改成了Resource URL.。这不是普通措辞细节:ResourceManager._loadSingleItem在:348-356有意把 virtualPath 交给 Loader,SpriteAtlasLoader.ts:31-54依赖它先解析逻辑相对页面,只有_request在ResourceManager.ts:201-204的叶子 I/O 边界映射物理地址。删掉这条公开 TSDoc 后,url看起来又可以被理解成 transport URL,正好遮蔽了本 PR 要固定的身份/地址边界。保留LoadItem.url为唯一逻辑请求身份、VFSpath为唯一物理地址;恢复一句简洁但明确的契约,例如说明注册虚拟资源时该字段保持 virtualPath 以供 Loader 解析依赖,不要重新增加resolvedUrl、wrapper 或第二份地址状态。
架构、熵增与测试治理
向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,registerVirtualResources 将其交给 ResourceManager;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,getResourceByRef 产生带 ?q= 的逻辑子资源请求,Loader 继续消费逻辑身份解析相对依赖,_request 才在叶子 I/O 边界映射物理地址,_subAssetPromiseCallbacks 与物理 _loadingPromises 协调主/子资源完成状态。
相较 ccf00ca14,本增量新增 0 个运行时 owner、状态、转换、校验、兼容分支或抽象,未引入 mirror/cache/wrapper/legacy fallback,执行熵没有增加;但 LoadItem.url 的公开契约信息减少了一层,形成问题 2 的认知熵。完整 PR 仍把 Texture 的两套解码状态机合并为一个 decodeImage owner,也没有为旧测试保留生产 compatibility branch。剩余运行时熵只有问题 1:完整 loading key 仍由 _loadSingleItem 拼装,取消入口只做完整字符串的精确 VFS 映射;收口后应只保留一条机械派生路径。测试侧,主资源 cache/cancel 已由公开链路覆盖,但 query 子资源取消仍无反向测试;权威契约没有需要保留的旧 fixture/mock/snapshot,也不应为现有测试增加 compatibility branch 或第二条转换路径。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮完整增量审查了 8608990efae4bf89e0746e46818b6f66ffea179a...ffe4bdafc8e6d31a23dc4f8976b9ea7fc5f09c9f 的 1 个提交、1 个文件,并回看完整 PR 的 8 个文件,沿 cancelNotLoaded 的 key 派生向上游 VFS 注册与 getResourceByRef 子资源请求、向下游 _loadingPromises 和 Loader I/O 各追一层。增量提交把单字符串取消从“临时单元素数组 + forEach 闭包”改为直接分支,把数组取消改为索引循环;对合法输入行为等价,没有新增状态、owner 或兼容路径,也未改变测试。上一轮 2 个 P2 仍未闭环,本轮未发现新的 P0/P1/P2;目标 HEAD 的 12 项 GitHub checks 均通过。阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 ffe4bdafc8e6d31a23dc4f8976b9ea7fc5f09c9f。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由348ebfa6e486648036c25d7db101b8ed0f045c70修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。LoadItem.resolvedUrl形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。- Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
- Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用
decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。 - 迁移分支夹带 clone/Shader 变更 — #3084 基于
dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656、53bb5b4542b6baa51d84247fde54878ddb78eedf已闭环单行注释、@ts-ignore说明和多行 TSDoc 标点。 - 主资源 cache/cancel 的逻辑/物理 key 双口径 —
ccf00ca14d5da98cd2f0522c8fe52f67cceb9810已让getFromCache(virtualPath)、cancelNotLoaded(virtualPath)、_onSubAssetSuccess与主资源加载复用_getRemoteUrl;公开链路测试能在旧实现上失败,且两个 pool 仍只保存物理 key。
问题
-
[P2] 让虚拟子资源取消复用加载链的完整 loading-key 派生,删除 query key 的第二套口径 —
packages/core/src/asset/ResourceManager.ts:158-163的新分支仍把调用方的完整字符串直接交给_getRemoteUrl,而该 helper 在:188-190只做完整 key 的 VFS 精确查表;加载路径却在:342-375,480先从Assets/model?q=materials[0]拆出基础 virtualPath,映射物理地址,再把子 promise 写到<physicalPath>?q=materials[0]。因此字符串和数组两个 overload 都仍会用逻辑 query key 索引,无法取消对应子资源 promise;现有tests/src/core/resource/ResourceManager.test.ts:206-229只覆盖无 query 的主资源。保留_parseURL/_parseQueryPath为 query 解析 owner、_virtualPathResourceMap为基础 virtualPath→physicalPath owner、物理_loadingPromises为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生收口为 load/cancel 共用的机械路径,删除_loadSingleItem的内联拼 key 和cancelNotLoaded的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开load(virtualPath + "?q=...")到cancelNotLoaded的反向测试。 -
[P2] 在
LoadItem.url上保留虚拟资源的逻辑身份契约,不要把关键边界写成泛化的 “Resource URL” —packages/core/src/asset/LoadItem.ts:30-33仍只写Resource URL.;但ResourceManager._loadSingleItem在:349-357有意把 virtualPath 交给 Loader,packages/loader/src/SpriteAtlasLoader.ts:31-54依赖它先解析逻辑相对页面,只有ResourceManager._request在:202-204的叶子 I/O 边界映射物理地址。当前 TSDoc 让url容易再次被理解为 transport URL,遮蔽了本 PR 要固定的身份/地址边界。保留LoadItem.url为唯一逻辑请求身份、VFSpath为唯一物理地址;恢复一句简洁但明确的契约,说明注册虚拟资源时该字段保持 virtualPath 以供 Loader 解析依赖,不要重新增加resolvedUrl、wrapper 或第二份地址状态。
架构、熵增与测试治理
向上游一层,Editor manifest / registerVirtualResources 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑子资源请求;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,Loader 继续消费逻辑身份解析相对依赖,_request 才在叶子 I/O 边界映射物理地址,_subAssetPromiseCallbacks 与物理 _loadingPromises 协调主/子资源完成和取消状态。
相较 8608990e,本增量新增 0 个运行时 owner、状态、转换、校验、兼容分支或抽象,删除了单字符串取消的 1 次临时数组分配和 forEach 闭包,执行熵略降;但它没有改变 key 语义,问题 1 的两条派生路径仍在。完整 PR 仍未引入 mirror/cache/wrapper/legacy fallback,Texture 的两套解码状态机已合并;问题 2 则继续保留一层公开契约认知熵。测试侧,本增量无需为等价遍历重写测试,既有主资源 cache/cancel 用例仍有效,但 query 子资源取消仍缺反向测试;未发现为旧测试保留的 production compatibility branch、legacy fixture/mock/snapshot 或第二条校验路径。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮完整增量审查了 ffe4bdafc8e6d31a23dc4f8976b9ea7fc5f09c9f...1e07682fe8ed9038c49fc0615d085f2a0547fea3 的 1 个提交、1 个文件,并回看完整 PR 的 8 个文件,沿 _onSubAssetSuccess 与完整 loading key 派生向上游 VFS 注册、getResourceByRef 和 Loader 子资源通知,向下游 _subAssetPromiseCallbacks、_loadingPromises 与叶子 I/O 各追一层。最新提交把子资源 callback map 的查找/创建收口为一次局部引用,行为与上一 HEAD 等价,减少一次顶层 map 访问和 4 行代码,没有新增状态、owner 或兼容路径;本轮未发现新的 P0/P1/P2,目标 HEAD 的 12 项 GitHub checks 均通过。上一轮 2 个 P2 仍未闭环,阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 1e07682fe8ed9038c49fc0615d085f2a0547fea3。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由348ebfa6e486648036c25d7db101b8ed0f045c70修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。LoadItem.resolvedUrl形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。- Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
- Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用
decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。 - 迁移分支夹带 clone/Shader 变更 — #3084 基于
dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656、53bb5b4542b6baa51d84247fde54878ddb78eedf已闭环单行注释、@ts-ignore说明和多行 TSDoc 标点;本增量的新单行注释形式也符合约定。 - 主资源 cache/cancel 的逻辑/物理 key 双口径 —
ccf00ca14d5da98cd2f0522c8fe52f67cceb9810已让getFromCache(virtualPath)、cancelNotLoaded(virtualPath)、_onSubAssetSuccess与主资源加载复用_getRemoteUrl;公开链路测试能在旧实现上失败,且两个 pool 仍只保存物理 key。
问题
-
[P2] 让虚拟子资源取消复用加载链的完整 loading-key 派生,删除 query key 的第二套口径 —
packages/core/src/asset/ResourceManager.ts:153-164仍把调用方的完整字符串直接交给_getRemoteUrl,而该 helper 在:188-190只做完整 key 的 VFS 精确查表;加载路径却在:336-405,476先从Assets/model?q=materials[0]拆出基础 virtualPath,映射物理地址,再把子 promise 写到<physicalPath>?q=materials[0]。因此字符串和数组两个 overload 都仍会用逻辑 query key 索引,无法取消对应子资源 promise;现有tests/src/core/resource/ResourceManager.test.ts:206-229只覆盖无 query 的主资源。保留_parseURL/_parseQueryPath为 query 解析 owner、_virtualPathResourceMap为基础 virtualPath→physicalPath owner、物理_loadingPromises为唯一状态;把“解析基础 URL → VFS 映射 → 规范化并拼回 query”的完整 key 派生收口为 load/cancel 共用的机械路径,删除_loadSingleItem的内联拼 key 和cancelNotLoaded的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开load(virtualPath + "?q=...")到cancelNotLoaded的反向测试。 -
[P2] 在
LoadItem.url上保留虚拟资源的逻辑身份契约,不要把关键边界写成泛化的 “Resource URL” —packages/core/src/asset/LoadItem.ts:30-33仍只写Resource URL.,最新增量又把ResourceManager.ts:347-353的身份说明缩成了“Only resolve unmapped relative URLs against baseUrl”;但packages/loader/src/SpriteAtlasLoader.ts:31-54依赖item.url先按逻辑路径解析相对页面,只有ResourceManager._request在:202-204的叶子 I/O 边界映射物理地址。当前 TSDoc 与相邻注释都没有固定本 PR 的核心身份/地址边界,容易让url再次被理解为 transport URL。保留LoadItem.url为唯一逻辑请求身份、VFSpath为唯一物理地址;恢复一句简洁但明确的公开契约,说明注册虚拟资源时该字段保持 virtualPath 以供 Loader 解析依赖,不要重新增加resolvedUrl、wrapper 或第二份地址状态。
架构、熵增与测试治理
向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑子资源请求;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,GLTF/RenderTarget Loader 通过 _onSubAssetSuccess 提供可提前交付的子资源,_subAssetPromiseCallbacks 只协调早到值与等待者,主资源完成后的 _getResolveResource 仍是权威 fallback;Loader 消费逻辑身份解析相对依赖,_request 才在叶子 I/O 边界映射物理地址。
相较 ffe4bdaf,本增量新增 0 个 owner、持久状态、转换、校验、兼容分支或抽象,复用既有 callback map,删除 1 个局部 remote key 和 1 次重复 map 访问,执行熵略降;callback 的 eager resolution 与主资源 fallback 没有增加第三份真相。完整 PR 仍未引入 mirror/cache/wrapper/legacy fallback,Texture 的两套解码状态机已合并;剩余运行时熵只有问题 1 的两条完整 loading-key 派生路径,问题 2 则保留公开契约认知熵。测试侧,本增量是等价收口,无需新增实现级测试;既有主资源 cache/cancel 与 Atlas/Texture 链路测试仍有效,但 query 子资源取消仍缺反向测试。未发现为旧测试保留的 production compatibility branch、legacy fixture/mock/snapshot 或第二条转换/校验路径。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮完整增量审查了 1e07682fe8ed9038c49fc0615d085f2a0547fea3...71d3e7c49ee65c416600553c078817495ed3b46c 的 1 个提交、1 个文件,并回看完整 PR 的 10 个提交、8 个文件,沿 Utils.resolveAbsoluteUrl 与完整 loading key 派生向上游 Project VFS 注册、getResourceByRef,向下游 SpriteAtlas/GLTF 相对依赖、子资源 promise 与叶子 I/O 各追一层。最新提交把非 scheme 路径的 href.slice("file:///".length) 等价收口为 pathname 加一次首斜杠裁剪;对 1,271 组覆盖绝对 URL、leading slash、Unicode、保留 %、query/hash 字面量的输入对比无行为差异,减少 4 行代码且没有新增状态、owner、兼容路径或测试负债。本轮未发现新的 P0/P1/P2,目标 HEAD 的 12 项 GitHub checks 均通过;上一轮 2 个 P2 仍未闭环,阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 71d3e7c49ee65c416600553c078817495ed3b46c。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由348ebfa6e486648036c25d7db101b8ed0f045c70修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。LoadItem.resolvedUrl形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。- Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
- Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用
decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。 - 迁移分支夹带 clone/Shader 变更 — #3084 基于
dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656、53bb5b4542b6baa51d84247fde54878ddb78eedf已闭环单行注释、@ts-ignore说明和多行 TSDoc 标点;本增量的新单行注释也符合约定并准确说明 empty file host 的作用。 - 主资源 cache/cancel 的逻辑/物理 key 双口径 —
ccf00ca14d5da98cd2f0522c8fe52f67cceb9810已让getFromCache(virtualPath)、cancelNotLoaded(virtualPath)、_onSubAssetSuccess与主资源加载复用_getRemoteUrl;公开链路测试能在旧实现上失败,且两个 pool 仍只保存物理 key。
问题
-
[P2] 让虚拟子资源取消复用加载链的完整 loading-key 派生,删除 query key 的第二套口径 —
packages/core/src/asset/ResourceManager.ts:153-164仍把调用方的完整字符串直接交给_getRemoteUrl,而该 helper 在:188-190只做完整 key 的 VFS 精确查表;加载路径却在:338-405,476先从Assets/model?q=materials[0]拆出基础 virtualPath,映射物理地址,再把子 promise 写到<physicalPath>?q=materials[0]。因此字符串和数组两个 overload 都会用逻辑 query key 索引,无法取消对应子资源 promise;上游getResourceByRef({ url, key })正会机械生成这种逻辑请求,而现有tests/src/core/resource/ResourceManager.test.ts:206-229只覆盖无 query 的主资源。保留_parseURL/_parseQueryPath为 query 解析 owner、_virtualPathResourceMap为基础 virtualPath→physicalPath owner、物理_loadingPromises为唯一状态;抽出 load/cancel 共用的“解析基础 URL → VFS 映射 → 规范化并拼回 query”机械派生,删除_loadSingleItem的内联拼 key 和cancelNotLoaded的完整字符串精确映射,不要增加 logical/physical 镜像 alias。补一条从公开load(virtualPath + "?q=...")到cancelNotLoaded的反向测试。 -
[P2] 在
LoadItem.url上保留虚拟资源的逻辑身份契约,不要把关键边界写成泛化的 “Resource URL” —packages/core/src/asset/LoadItem.ts:30-33仍只写Resource URL.,而ResourceManager.ts:344-354有意把 virtualPath 交给 Loader,packages/loader/src/SpriteAtlasLoader.ts:31-54依赖它先按逻辑路径解析相对页面,只有ResourceManager._request在:200-204的叶子 I/O 边界映射物理地址。最新增量对Utils注释的收口准确解释了路径保大小写,却没有固定这个公开身份/地址契约,url仍容易被理解为 transport URL。保留LoadItem.url为唯一逻辑请求身份、VFSpath为唯一物理地址;在该公开 TSDoc 中明确注册虚拟资源时字段保持 virtualPath 供 Loader 解析依赖,不要重新增加resolvedUrl、wrapper 或第二份地址状态。
架构、熵增与测试治理
向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑子资源请求;ResourceManager 应唯一拥有 virtualPath→physicalPath、loader 选择和完整 cache/loading key 派生。向下游一层,SpriteAtlas/GLTF 以逻辑身份解析相对依赖,GLTF/RenderTarget 通过 _onSubAssetSuccess 提前交付子资源,_subAssetPromiseCallbacks 只协调早到值与等待者,主资源完成后的 _getResolveResource 仍是权威 fallback;_request 才在叶子 I/O 边界映射物理地址。
相较 1e07682f,本增量新增 0 个 owner、持久状态、转换、校验、兼容分支或抽象,删除 1 个局部 head、收短 4 行注释并复用 URL 的 pathname 结果,概念与执行熵略降;现有 Utils 与 Atlas 链路测试继续覆盖本次等价重构,无需为实现写新测试。完整 PR 仍未引入 mirror/cache/wrapper/legacy fallback,Texture 的两套解码状态机已合并;剩余运行时熵只有问题 1 的两条完整 loading-key 派生路径,问题 2 则保留公开契约认知熵。测试侧,主资源 cache/cancel 与 Atlas/Texture 链路测试仍有效,但 query 子资源取消仍缺反向测试;未发现为旧测试保留的 production compatibility branch、legacy fixture/mock/snapshot 或第二条转换/校验路径。
GuoLei1990
left a comment
There was a problem hiding this comment.
🫧 尘小沫
结论
本轮完整增量审查了 71d3e7c49ee65c416600553c078817495ed3b46c...b83bdd0eee638261155fd89bfed9bd2c1ddba16d 的 1 个提交、2 个文件,并回看完整 PR 的 11 个提交、8 个文件,沿物理 asset key 派生向上游 Project VFS 注册、getResourceByRef,向下游 SpriteAtlas/GLTF/RenderTarget Loader、子资源 callback、cache/loading pool 与叶子 I/O 各追一层。最新提交已闭环上一轮虚拟 query 子资源无法按逻辑路径取消的问题,并把同根因的 baseUrl 相对资源 cache/cancel key 一并收口;新增三条公开链路测试可反向守住旧实现。本轮未发现新的 P0/P1/P2,目标 HEAD 的 12 项 GitHub checks 均通过;仍有 1 个公开契约 P2 未闭环,阻塞级别为 P2(不阻塞),实际 review 动作为 COMMENTED,目标 HEAD 为 b83bdd0eee638261155fd89bfed9bd2c1ddba16d。自动 CR 不替代人工 Reviewer 的合入门禁,仍需人工审核确认。
已关闭问题清单
baseUrl覆盖虚拟资源逻辑身份 — 已由348ebfa6e486648036c25d7db101b8ed0f045c70修复;VFS 命中时 Loader 收到 logical virtualPath,Atlas 相对页面依赖再回到 ResourceManager 映射。LoadItem.resolvedUrl形成逻辑/物理双源 — 当前公开类型、生产写入与 fixture 均无该字段,物理地址只保留在 VFS 表及内部 I/O/cache/loading 边界。- Shader 以物理 URL 作为 include 基址或表示格式判据 — 当前仍以逻辑 URL 解析 include、以 payload 判断源码/预编译表示,本 PR 未恢复后缀判型或第二条请求路径。
- Texture 首次解码与内容恢复维护平行状态机 — 两条路径已统一复用
decodeImage,Image/Object URL 生命周期和错误契约只有一个 owner,恢复失败测试可反向守住。 - 迁移分支夹带 clone/Shader 变更 — #3084 基于
dev/2.0,完整 diff 仍仅包含 8 个 loader/VFS 相关文件,标题、正文和变更单元一致。 - 新增注释不符合仓库约定 —
07a8d6a11649e6f95ac1262e1bb9b3e055919930、d5735fa7c60549959513415ffad0621457243656、53bb5b4542b6baa51d84247fde54878ddb78eedf已闭环单行注释、@ts-ignore说明和多行 TSDoc 标点;本增量的新单行注释也准确且符合约定。 - 主资源 cache/cancel 的逻辑/物理 key 双口径 —
ccf00ca14d5da98cd2f0522c8fe52f67cceb9810已让公开 cache/cancel 与主资源加载复用 VFS 物理映射,两个 pool 仍只保存物理 key。 - 虚拟 query 子资源与
baseUrl相对资源存在第二套 loading/cache key 口径 —b83bdd0eee638261155fd89bfed9bd2c1ddba16d已让_getRemoteUrl唯一拥有 VFS/baseUrl 基础物理 key,让_getRemoteAssetURL唯一拥有 query key 格式;load、cache、cancel 与子资源 callback 机械复用,且新增公开链路测试覆盖两类旧失配。
问题
- [P2] 在
LoadItem.url的公开 TSDoc 中固定虚拟资源的逻辑身份契约 —packages/core/src/asset/LoadItem.ts:30-33仍只写Resource URL.;最新提交在packages/core/src/asset/ResourceManager.ts:348-350增加的// Preserve virtual paths for loaders准确记录了内部实现意图,但自定义 Loader 作者仍无法从公开类型得知:VFS 命中时item.url保持 virtualPath,SpriteAtlas 在packages/loader/src/SpriteAtlasLoader.ts:53用它解析相对依赖,GLTF 在packages/loader/src/GLTFLoader.ts:41用它作为资源基址,只有_request才映射物理地址。保留LoadItem.url为唯一 Loader 可见的逻辑请求身份、VFSpath为唯一物理地址;把这一条件契约写回该公开 TSDoc,不要重新增加resolvedUrl、wrapper、镜像字段或第二条地址转换路径。
架构、熵增与测试治理
向上游一层,ProjectLoader / Editor manifest 唯一拥有 { virtualPath, path, type } 注册事实,getResourceByRef 只从该事实机械生成带 ?q= 的逻辑请求;ResourceManager 唯一拥有 virtualPath/baseUrl→physical base key、query loading key、loader 选择和 cache/loading 状态。向下游一层,SpriteAtlas/GLTF/RenderTarget Loader 继续以逻辑身份解析依赖或通知子资源,_subAssetPromiseCallbacks 只协调早到值与等待者,_request 才在叶子 I/O 边界取物理地址。
相较 71d3e7c4,本增量新增 0 个持久状态、镜像 key、校验、兼容分支或 legacy fallback;增加 2 个无状态 private helper,同时删除 load/cancel 中两处内联物理 key 拼装,使 VFS/baseUrl 映射与 query 序列化各只剩一个 owner,没有把复杂度转移给 Loader 或测试。测试侧新增 baseUrl cache、baseUrl cancel、虚拟 query 子资源 cancel 三条公开链路用例,并为既有 pending fixture 补齐 catch/cancel 清理;未发现为旧测试保留的 production compatibility branch、失效 fixture/mock/snapshot 或第二条转换/校验路径。剩余熵仅是问题 1 的公开契约认知缺口。
问题
Editor Preview 会将工程文件注册为 VFS 虚拟资源。SpriteAtlas 元数据中的页面路径
./auto-atlas_image_0.tex,必须先基于 Atlas 的逻辑路径SpriteAtlas/.../auto-atlas.atlas推导为SpriteAtlas/.../auto-atlas_image_0.tex,再由ResourceManager映射到 Blob 或 CDN 等物理加载地址。此前
LoadItem.url在进入 Loader 前被改写为物理 URL;后续相对路径推导随之基于物理 URL 运行,VFS key 因而丢失。对于无 scheme 的路径,原先的file://用法还会把首段当作 host 并按 URL 规则小写化,导致SpriteAtlas/...被请求为spriteatlas/...,Preview 无法启动。修复
LoadItem.url始终保留virtualPath;baseUrl只作用于普通、未注册的相对传输 URL。ResourceManager的加载、子资源回调、缓存查询与取消统一通过_getRemoteUrl派生物理 key;内部 cache/loading pool 仍只保存一份物理 key。file:///的 pathname 解析,避免首段进入 host 规范化,并保留 leading slash 语义。覆盖
baseUrl不会改写已注册 VFS key。分支边界
这是 #3079 在
dev/2.0上的等价修复:基于dev/2.0@bd34daa重放 #3079 的最终 loader 改动。后续提交仅对齐项目的英文注释规范并闭环 review 反馈,不包含迁移分支的其他提交。验证
HEADLESS=true pnpm vitest run:124 files / 1658 tests passedpnpm b:modulepnpm b:types:12 个 package project 均通过pnpm lint:0 errors;1622 existing warningspnpm format:check与改动测试文件的 Prettier checkgit diff --checkSummary by CodeRabbit