# Spine 运行时 vendor 补丁记录 > ⚠️ **升级 `spine-canvas.js` / `spine-webgl.js` 前必读。** > 这两个文件**不是官方发行版原样**,含本地补丁。直接用官方文件覆盖会导致 > `file://` 协议下资源加载全部失败(表现:所有 Spine 特效不显示)。 ## 基线版本 | 文件 | npm 包 | 基线版本 | 字节数 | sha256 | |---|---|---|---|---| | `spine-canvas.js` | `@esotericsoftware/spine-canvas` | **4.2.113**(与 4.2.114 官方产物完全相同) | 455670 | `a19ad49c42490d4f41dbc805b0b91d72ccca4236957b2cdab8e57483c3aeb45c` | | `spine-webgl.js` | `@esotericsoftware/spine-webgl` | **4.2.113** | 553987 | `0c2a0d8cb833297168bac7bbb7821d6ebe87aa11c3708831ca6741468b3d4d25` | 骨架资源导出版本为 **4.2.43**(见 `client/assets/spine/*.json` 的 `skeleton.spine` 字段), 运行时须保持在 **4.2.x** 系列。 官方产物获取地址: ``` https://cdn.jsdelivr.net/npm/@esotericsoftware/spine-canvas@4.2.113/dist/iife/spine-canvas.js https://cdn.jsdelivr.net/npm/@esotericsoftware/spine-webgl@4.2.113/dist/iife/spine-webgl.js ``` 官方原始产物 sha256(用于确认下载无误): - spine-canvas 4.2.113/114:`b706c28a…`(4.2.43 版,仅作对照,非本项目基线) - spine-webgl 4.2.113:`e737ac4e7caa9fae…`(打补丁前) --- ## 补丁清单 ### 补丁 1 —— `file://` 下不设 `crossOrigin` **应用于**:`spine-canvas.js`、`spine-webgl.js` **位置**:`AssetManager.loadTexture` 中构造 `Image` 处(canvas 版约 5798 行 / webgl 版约 5838 行)。 **原因**:`file://` 协议下设置 `image.crossOrigin = "anonymous"` 会使图片被判为跨域而加载失败。 这是 PNG 图集能在 `file://` 下加载的关键。 ```js // 官方 image.crossOrigin = "anonymous"; // 本地 if (typeof location === "undefined" || location.protocol !== "file:") image.crossOrigin = "anonymous"; ``` ⚠️ 只改 `loadTexture` 中的 `image`。webgl 版另有 `logoImage` / `spinnerImage` (约 14004 / 14008 行,属 loading spinner),**不要动**。 --- ### 补丁 2 —— 删除 `toLoad === 0` 提前 resolve 分支 **应用于**:仅 `spine-canvas.js`(**`spine-webgl.js` 未移植,保留官方逻辑**) **位置**:`AssetManager.loadTextureAtlas`(canvas 版官方约 5826-5830 行)。 ```js // 官方(webgl 版保留此段) if (toLoad === 0) { this.success(success, path, atlas); resolve(atlas); return; } ``` **行为差异**:官方在 `atlas.pages.length === 0` 时立即 resolve;删除后该情形下 Promise 永不 resolve,`isLoadingComplete()` 恒为 false,全部 Spine 都不会显示。 **未移植到 webgl 版的理由**:本项目 20 个 atlas 文件实测**全部至少 1 页**(共 23 页), 该分支在本项目不可达,删与不删行为完全相同;而官方逻辑在边界情形下更安全。 **注**:此补丁在 `spine-canvas.js` 中随 commit `1f48f4ea`(2026-04-20)打包引入, 提交信息未提及,**原始意图在仓库中无记录可考**。上述为行为分析,非意图推定。 --- ### 补丁 3 —— `rawDataUri` 判定改为 `startsWith("data:")` **应用于**:`spine-canvas.js`(仅 `downloadText`)、`spine-webgl.js`(`downloadText` + `downloadBinary`) **位置**:`Downloader.downloadText` / `Downloader.downloadBinary` (canvas 版约 6070 / 6096 行,webgl 版约 6110 / 6136 行)。 ```js // 官方 if (rawDataUri && !rawDataUri.includes(".")) { // 本地 if (rawDataUri && rawDataUri.startsWith("data:")) { ``` **原因**:`SpineMgr.js` 用 `setRawDataURI(key, "data:," + textData[key])` 注入嵌入的 json/atlas 文本(见 `client/generated/spine_data.js`),以规避 `file://` 下 XHR 的 CORS 拦截。 而 json 文本中必然含小数点(坐标、版本号等),官方那个「不含点才算 data URI」的判定会误判为 非 data URI,导致回退到 XHR 请求而失败。 **两版差异说明**:`spine-canvas.js` 只改了 `downloadText`,因为本项目只用 `loadText` (json/atlas 均为文本),不走二进制 `.skel` 路径。`spine-webgl.js` 两处都改了 —— 该判定本身是官方的缺陷逻辑,改为 `startsWith("data:")` 在两处均为纯正确性提升、无副作用。 --- ## 升级流程 1. 从上述 CDN 取目标版本的官方 iife 产物,记录其原始 sha256。 2. 逐条比对本文件的补丁清单,确认每处补丁点在新版中仍存在且语境未变。 3. 移植补丁时**必须校验匹配次数**(补丁 1 应命中 1 处、补丁 3 应命中 2 处), 匹配数不符即中止并重新核对,不得盲替。 4. 验证产物:`node --check` 语法检查;用 vm 加载并确认关键 API 齐备 (`AssetManager` / `SkeletonJson` / `AtlasAttachmentLoader` / `Skeleton` / `AnimationState` / `AnimationStateData` / `Physics` / `TextureAtlas`, webgl 版另需 `SceneRenderer` / `PolygonBatcher` / `GLTexture` / `ManagedWebGLRenderingContext`)。 5. 更新本文件的版本号与 sha256。 6. 真机验证 `file://` 下资源加载正常(补丁 1、3 的实际验收点)。 ## 已知约束 两个文件都以 `var spine = (() => {...})()` 形式暴露**同一个全局名 `spine`**。 **同时加载两者会互相覆盖**,后加载的胜出。因此运行时只能加载其中一个, 或在两次加载之间抢存引用。相关设计见 `docs/superpowers/specs/2026-08-08-spine-webgl-migration-design.md`。