Skip to content

t1k:cocos:base:uuid-verify

FieldValue
Modulebase
Version1.14.0
Efforthigh
Tools

Keywords: attach, cocos, component, dry-run, js2ts, meta, migration, prefab, uuid

/t1k:cocos:base:uuid-verify

Sau khi t1k-cocos-base-js2ts đã sinh .cv.ts (đã tsc-validate), dùng skill này để gắn TS component vào prefab/scene — tức làm cho bản TS chạy thật trong game — mà KHÔNG xóa JS (coexistence). Đây là bước uuid-verify / attach trong pipeline (lưu ý: bước cutover/xóa-JS đã GỠ khỏi pipeline theo quyết định 2026-05-31; skill này thay nó bằng cơ chế re-point không-phá-hủy).

Pipeline active: dep-graph → scope-audit(read) → js2ts → tsc-validate → uuid-verify(attach).

KHÔNG dùng cho: xóa JS, transplant uuid cũ (đó là cutover — đã hoãn); chỉnh sửa logic.

Cơ chế (đã research trên chính project này)

Section titled “Cơ chế (đã research trên chính project này)”
  1. Prefab/scene = JSON thuần (verify: 163/163 file, 0 binary). Object liên kết qua {"__id__": idx}.
  2. Component class được tham chiếu qua compressed-uuid ở các field:
    • __type__ — instance của component trên 1 node
    • _componentId — component đích trong event-handler (Button click → method)
    • __uuid__ — asset-ref tới script (hiếm) Cả ba đều trỏ cùng class → đều phải re-point cùng. (fileId của PrefabInfo dài 22 ký tự → bị loại; compressed-uuid là 23 ký tự.)
  3. Codec compressed-uuid (Cocos 2.x, đã verify round-trip): 5 hex literal + (mỗi 3 hex → 2 base64)×9 = 18 base64 = 23 ký tự. BASE64 = A-Za-z0-9+/.
  4. @property serialize THEO TÊN (không theo thứ tự) → binding giữ nguyên IFF class TS có đủ @property cùng tên (own + inherited qua extends).
  5. cc.PrefabInfo (root/asset/fileId/sync) KHÔNG ref class → re-point trực giao, không đụng.

scripts/uuid-verify.cjs — Node, pure file-based, mặc định DRY-RUN:

LệnhViệc
reportTổng quan: liệt kê .cv.ts, JS-uuid khớp, số ref prefab/scene, có .meta chưa, cần re-point hay chỉ gen-meta
gen-meta [<file.cv.ts>] [--write]Sinh .cv.ts.meta (uuid mới) cho closure import của 1 file, HOẶC tất cả .cv.ts (không truyền file). Additive thuần — chỉ tạo .meta mới
attach <file.cv.ts> [--write](a) gen .cv.ts.meta cho target + TOÀN BỘ closure import (để runtime require resolve) → (b) gate completeness @property (serialized keys ⊆ TS chain) → (c) re-point mọi __type__/_componentId/__uuid__ trong prefab/.fire
verifyHealth-check toàn project: dangling (uuid resolve về .meta?) + isPlugin (mọi .cv.ts.meta=false?) + editor-compile-verify (mọi .cv đã attach có library/imports/<uuid>.js?)
verify --scene <path>Như verify nhưng scoped 1 prefab/scene: liệt kê đúng component của file đó — đã-TS (compiled? isPlugin?) / còn-JS (convert chưa?) / dangling. Exit 2 nếu có vấn đề. Dùng để xác nhận 1 prefab sau khi attach.

Gate FAIL (thiếu @property → mất binding) hoặc gặp key tham chiếu lạ → dừng (exit 2), trừ khi --force.

Terminal window
# Tổng quan (read-only):
node .claude/skills/t1k-cocos-base-uuid-verify/scripts/uuid-verify.cjs report
# Sinh .meta cho TẤT CẢ .cv.ts (làm editor thấy + require closure resolve):
node .claude/skills/t1k-cocos-base-uuid-verify/scripts/uuid-verify.cjs gen-meta --write
# Dry-run attach 1 component (KHÔNG ghi gì — xem trước):
node .claude/skills/t1k-cocos-base-uuid-verify/scripts/uuid-verify.cjs attach Client/assets/script/scripts/MapPage.cv.ts
# Áp dụng thật (tạo .meta + ghi prefab/scene; JS vẫn nguyên):
node .claude/skills/t1k-cocos-base-uuid-verify/scripts/uuid-verify.cjs attach Client/assets/script/scripts/MapPage.cv.ts --write
# Kiểm dangling toàn project:
node .claude/skills/t1k-cocos-base-uuid-verify/scripts/uuid-verify.cjs verify

Flags: --registry · --script-root · --assets-root · --scene <path> (verify scoped 1 prefab/scene) · --write (bật ghi) · --force (bỏ qua gate-fail/key-lạ — DÙNG CẨN THẬN).

Đường dẫn (registry/script-root/assets-root) lấy từ .claude/cocos-migrate.json (SSOT dùng chung, KHÔNG hardcode); CLI flag > config > fallback. Xem t1k-cocos-base-migrate § Config.

  • 158 compressed-uuid được prefab/scene tham chiếu → 148 khớp script registry (tất cả isComponent=true), 7 editor-only JS (assets/editor/, ngoài scope), 3 đã là .ts. 0 dangling.
  • Chỉ 148/434 script được đặt trong prefab/scene = tập cần attach. ~286 còn lại là logic-only / base-class / runtime-add → chỉ cần gen-meta (nếu muốn editor thấy), KHÔNG re-point.
  • VD: MapPage (1 instance + 10 event-handler ref trong main.fire) cần re-point; Avatar (add runtime), Menu (base), pc/LevelManager (logic) KHÔNG có ref prefab.
  1. Bề mặt tham chiếu KHÔNG chỉ __type__. _componentId (event-handler) cũng trỏ component class — phát hiện khi test MapPage (1 __type__ + 10 _componentId). Bỏ sót _componentId → handler trỏ component cũ → vỡ. Tool quét MỌI field compressed-uuid; report/attach in breakdown theo key để audit.

  2. Re-point bằng string-replace ("<compFrom>""<compTo>") — giữ format file y nguyên (diff tối thiểu). An toàn vì compressed-uuid là token 23-ký-tự duy nhất của đúng asset đó. Tránh JSON.parse→stringify (sẽ reformat cả file → diff khổng lồ).

  3. Gate completeness BẮT BUỘC trước re-point. Serialized @property key (own + inherited) phải ⊆ @property của TS chain. Thiếu → mất binding → dừng. Cần convert base chain trước (vd Menu.cv.ts trước MapPage.cv.ts) để tsPropChain lấy đủ inherited.

  4. uuid mới persist trong .meta → idempotent: chạy lại không đổi uuid (chỉ tạo nếu .meta chưa có). Dry-run KHÔNG persist nên mỗi lần in uuid khác — bình thường.

  5. JS không bao giờ bị đụng — chỉ tạo .cv.ts.meta mới + sửa __type__/_componentId trong prefab/scene. Revert = git checkout các prefab/scene.

  6. Key tham chiếu lạ (không phải __type__/_componentId/__uuid__) → tool dừng, yêu cầu audit thủ công (--force để bỏ qua nếu chắc).

  7. --uuid__ với sub-asset ("uuid@sub", >23 ký tự) hiện bị isCompUuid bỏ qua — chưa gặp với script component; bổ sung nếu phát sinh.

  8. Closure import phải loadable. Khi Cocos load component TS, nó chạy require("./Dep.cv") cho mọi dep đã convert → mỗi .cv.ts trong closure phải có .meta mới resolve runtime. attach tự gen-meta cả closure (theo require/from/side-effect import, chỉ đệ quy .cv.ts); chạy gen-meta (all) trước khi attach hàng loạt là cách an toàn. Dep KHÔNG phải .cv (Plugin/.ts-sẵn/.js live) đã có .meta riêng → bỏ qua đúng.

  9. isPlugin:true = component CHẾT IM LẶNG (gotcha nguy hiểm nhất). Khi editor mở live tự auto-import .cv.ts, nó CÓ THỂ tạo .cv.ts.meta với "isPlugin": true + "loadPluginInEditor": false. Khi đó Cocos coi script là pluginKHÔNG compile như component, KHÔNG nạp trong editor → class không register → scene báo “Script … is missing or invalid / Error on compiling script” NHƯNG KHÔNG có dòng lỗi nào trong Console panel lẫn CocosCreator.log (bị bỏ qua có chủ đích, không phải compile-fail). Đặc trưng để nhận diện: tsc/transpileModule offline compile SẠCH, không sinh library/imports/<uuid>.js, không thấy “Should not specify class name X_cv” cho file đó (file khác thì có). FIX: sửa .meta thành "isPlugin": false rồi reimport (editor sẽ giữ false và compile như component → sinh library entry). Tool tự phát hiện + sửa (cần --write) trong attach/gen-meta; lệnh verify quét cảnh báo mọi .cv.ts.meta còn isPlugin:true. Cocos 2.4.x compile .ts bằng tsc bundled (TS 4.1.3), compile .js bằng Babel — đây là 2 đường khác nhau.

  10. Single-writer uuid — chạy pipeline với editor ĐÓNG (quyết định canonical 2026-06-01, hướng cho mọi project sau). Để migration ĐỒNG BỘ (tái lập, sai-đồng-bộ/đúng-đồng-bộ), .cv.ts.meta chỉ được có MỘT người ghi. Cocos editor mở-live cũng auto-import .cv.ts + tự gán uuid (+ có thể isPlugin:true, xem gotcha 9) → nếu cả editor lẫn tool cùng ghi .meta, uuid mà prefab được re-point tới phụ thuộc TIMING import = BẤT ĐỊNH. Cocos KHÔNG có khái niệm “locked meta” nên không thể nhờ editor nhường ⇒ phương án “hybrid (tool gán + phát hiện lệch)” KHÔNG đạt đồng bộ thật (vẫn 2 writer, chỉ fail-loud). Protocol canonical (tool-owns): (1) ĐÓNG editor khi chạy gen-meta/attach; (2) tool ghi toàn bộ .cv.ts.meta (uuid + isPlugin:false); (3) MỞ editor SAU → Cocos tôn trọng .meta đã có (không gán lại uuid khi meta hợp lệ) → compile; (4) verify (editor-compile-verify) xác nhận. Project sau theo hướng này — KHÔNG để editor mở lúc gắn uuid. Liên quan memory project_cocos_editor_live_meta (đã cập nhật theo quyết định này).

  • t1k-cocos-base-js2ts — sinh .cv.ts (chạy trước).
  • t1k-cocos-base-dep-graph — registry (JS-uuid + isComponent).
  • plans/reports/2026-05-29-js-to-ts-migration-brainstorm.md — banner đầu doc: cutover/xóa-JS đã hoãn; skill này là cơ chế attach không-phá-hủy thay thế.