|
| 1 | +# Native Module .node Injection (gl / sharp ABI Adaptation for Host Electron) |
| 2 | + |
| 3 | +## Background |
| 4 | + |
| 5 | +cocos-cli depends on two native modules: |
| 6 | + |
| 7 | +- `gl` (headless-gl): loads `build/Release/webgl.node` via `bindings('webgl')` |
| 8 | +- `sharp`: loads its native binding via `require('../build/Release/sharp-<platformAndArch>.node')` |
| 9 | + |
| 10 | +These `.node` binaries are tightly coupled to the ABI of the Node/Electron runtime that |
| 11 | +loads them. When a cocos-cli process is started by a host Electron runtime (e.g. pink / |
| 12 | +Cocos Creator editor), the `.node` binaries bundled with cocos-cli may not match the |
| 13 | +host's Electron version, causing load failures. |
| 14 | + |
| 15 | +## Mechanism |
| 16 | + |
| 17 | +Via patch-package patches (`patches/gl+9.0.0-rc.10.patch`, `patches/sharp+0.32.6.patch`), |
| 18 | +the gl / sharp native binding loaders read environment variables. When an env var is |
| 19 | +set, the `.node` file at the specified path is loaded; otherwise the bundled default |
| 20 | +binary is used. **When unset, behavior is identical to before.** |
| 21 | + |
| 22 | +## Env Var Contract (host side) |
| 23 | + |
| 24 | +| Env var | Meaning | Example value | |
| 25 | +|---|---|---| |
| 26 | +| `COCOS_CLI_GL_NODE` | Path to the gl (webgl) native binding `.node` | `/path/to/electron/webgl.node` | |
| 27 | +| `COCOS_CLI_SHARP_NODE` | Path to the sharp native binding `.node` | `/path/to/electron/sharp-darwin-arm64v8.node` | |
| 28 | + |
| 29 | +> The path should be absolute. When unset or empty, cocos-cli falls back to its bundled `.node`. |
| 30 | +
|
| 31 | +### pink CocosMainService usage example |
| 32 | + |
| 33 | +Pass the env vars when spawning the cocos-cli process: |
| 34 | + |
| 35 | +```ts |
| 36 | +const child = spawn(cocosCliEntry, args, { |
| 37 | + env: { |
| 38 | + ...process.env, |
| 39 | + COCOS_CLI_GL_NODE: path.join(pinkNativeDir, 'webgl.node'), |
| 40 | + COCOS_CLI_SHARP_NODE: path.join(pinkNativeDir, 'sharp-darwin-arm64v8.node'), |
| 41 | + }, |
| 42 | +}); |
| 43 | +``` |
| 44 | + |
| 45 | +## Child Process Propagation |
| 46 | + |
| 47 | +cocos-cli's internal child processes (effect compilation, builder workers, scene process, |
| 48 | +script/engine compilation, etc.) are launched via `spawn`/`fork` without an explicit `env` |
| 49 | +override, so they **automatically inherit** the main process env vars. The host only needs |
| 50 | +to set the env vars on the main process to cover the whole chain. |
| 51 | + |
| 52 | +## Patch Maintenance |
| 53 | + |
| 54 | +- Patch files: `patches/gl+9.0.0-rc.10.patch`, `patches/sharp+0.32.6.patch` |
| 55 | +- Apply/rebuild: `npm run rebuild` (runs patch-package + @electron/rebuild) |
| 56 | +- Apply manually: `npx patch-package` |
| 57 | +- Regenerate patches (after modifying node_modules): |
| 58 | + |
| 59 | + ```sh |
| 60 | + npx patch-package gl sharp --exclude 'build/|node-addon-api' |
| 61 | + ``` |
| 62 | + |
| 63 | + > Note: passing multiple `--exclude` values merges them into a single regex (with a |
| 64 | + > literal comma), so use an alternation inside one regex (e.g. `'build/|node-addon-api'`); |
| 65 | + > paths are relative to the package root (no leading `/`), so `build/` matches `build/...`. |
0 commit comments