Skip to content

feat(workflow): node-gyp rebuild for nodejs packages; re-apply gl/sharp .node injection (#858) - #867

Open
looopmax wants to merge 4 commits into
cocos:mainfrom
looopmax:feat/rebuild-node-support
Open

feat(workflow): node-gyp rebuild for nodejs packages; re-apply gl/sharp .node injection (#858)#867
looopmax wants to merge 4 commits into
cocos:mainfrom
looopmax:feat/rebuild-node-support

Conversation

@looopmax

@looopmax looopmax commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Changes

1. feat(workflow): rebuild native node-gyp modules for nodejs packages (c1267fb)

During release, rebuild native modules for nodejs-type packages via patch-package + npm rebuild.

  • add workflow/node-gyp-rebuild.js
  • add rebuild:node-gyp npm script
  • run the rebuild step in release pipeline for non-electron packages

2. re-apply gl/sharp native .node injection via env vars (#858)

Re-applies the changes from #858 (previously reverted wholesale in #865; this is an exact revert-of-revert):

  • .gitignore: ignore perf/
  • docs/dev/native-modules-injection.md: new doc describing the gl/sharp native binding injection mechanism
  • patches/gl+9.0.0-rc.10.patch: native-gl.js supports injection via the COCOS_CLI_GL_NODE env var
  • patches/sharp+0.32.6.patch: new patch, supports injection via the COCOS_CLI_SHARP_NODE env var

Difference from the original PR: the #858 change to workflow/release.js (unconditional npm run rebuild) is not re-applied, because this branch's rebuild:node-gyp step already covers that need, and both rebuild paths run patch-package.

Verification

  • npm run rebuild (patch-package + @electron/rebuild 42.3.0) passes; all three patches (gl / nan / sharp) apply successfully
  • Functional check: with COCOS_CLI_GL_NODE / COCOS_CLI_SHARP_NODE set, requiring the corresponding module prints the injection log and loads the specified .node; without them, behavior is identical to before

@looopmax
looopmax marked this pull request as draft August 19, 2026 07:51
@looopmax looopmax changed the title feat(workflow): rebuild native node-gyp modules for nodejs packages feat(workflow): node-gyp rebuild for nodejs packages; re-apply gl/sharp .node injection (#858) Aug 19, 2026
@looopmax
looopmax marked this pull request as ready for review August 19, 2026 08:37
@looopmax looopmax closed this Aug 19, 2026
@looopmax looopmax reopened this Aug 19, 2026
@looopmax
looopmax force-pushed the feat/rebuild-node-support branch from ced0a12 to 1222b9b Compare August 19, 2026 12:57
@wuzhiming
wuzhiming self-requested a review August 20, 2026 06:26
@looopmax
looopmax force-pushed the feat/rebuild-node-support branch from bbdf533 to 1222b9b Compare August 20, 2026 07:46

@wuzhiming wuzhiming left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two items from reviewing the release-pipeline side of this. The node-gyp-rebuild.js one is blocking — the new nodejs rebuild step can't run at all as written. Details inline.

@@ -0,0 +1,14 @@
const { execSync } = require('child_process');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Blocking: this file never reaches the release directory, so rebuild:node-gyp always fails

.vscodeignore whitelists only three .js files under workflow/:

workflow/!(postinstall|utils|electron-rebuild).js

release.js builds its copy list from exactly those patterns (readIgnorePatterns -> scanProjectFiles), so workflow/node-gyp-rebuild.js is filtered out and never lands in the publish dir. Running the pipeline's own globby call on this branch, these are the only workflow/ entries that get copied:

workflow/electron-rebuild.js
workflow/generate-dts-postprocess.ts
workflow/generate-dts-worker.mjs
workflow/generate-dts.ts
workflow/postinstall.js
workflow/utils.js

Repro:

node -e "(async()=>{const {globby}=await import('globby');const fs=require('fs');
const p=fs.readFileSync('.vscodeignore','utf8').split('\n').map(l=>l.trim()).filter(l=>l&&!l.startsWith('#'));
p.push('.publish/**');
const f=await globby(['**/*'],{cwd:process.cwd(),dot:true,ignore:p,onlyFiles:true});
console.log(f.filter(x=>x.startsWith('workflow/')));})()"

So npm run rebuild:node-gyp in the release dir exits with MODULE_NOT_FOUND, and runCommand rejects on any non-zero exit (workflow/utils.js) — which fails the entire nodejs release pipeline, not just this step.

Two ways to fix:

  1. Whitelist the new file:
    workflow/!(postinstall|utils|electron-rebuild|node-gyp-rebuild).js
    
  2. Or drop the new file and add a flag to electron-rebuild.js, which is already whitelisted — one less thing to keep in sync between workflow/ and .vscodeignore:
    run('npx --yes patch-package');
    if (process.argv.includes('--node')) {
        run('npm rebuild');
    } else {
        run(`npx @electron/rebuild --force --version ${electronVersion}`);
    }
    with "rebuild:node-gyp": "node workflow/electron-rebuild.js --node".

Either way, could you verify with an actual --nodejs release rather than npm run rebuild alone? The Verification section only exercises the electron path, which is the one that already worked — the new path is the one that's broken.

@@ -0,0 +1,18 @@
diff --git a/node_modules/sharp/lib/sharp.js b/node_modules/sharp/lib/sharp.js

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sharp is a caret range, but the patch filename pins 0.32.6 — and a stale patch here fails silently

package.json declares "sharp": "^0.32.6", while patch-package resolves patches by exact <name>+<version> in the filename. Once a fresh install resolves 0.32.7+, two things can happen, and from patch-package@8.0.1's applyPatches.js neither is loud in our setup:

  • Mismatch, patch still applies -> goes to warnings. Exit code stays 0 unless --error-on-warn is passed.
  • Mismatch, patch fails to apply -> goes to errors via createPatchApplicationFailureError, but the exit code is still 0 unless shouldExitWithError is true, which requires --error-on-fail, NODE_ENV=test, or ci-info's isCI.

npm run release isn't invoked from any workflow in .github/workflows/, so releases are cut manually and isCI is false. Net effect: a patch can fail outright and the release still completes green — COCOS_CLI_SHARP_NODE would then be silently ignored at runtime, which is exactly the failure mode this PR exists to prevent.

Suggest both:

  • Pin the exact version: "sharp": "0.32.6"
  • Add --error-on-fail to patch-package in both rebuild scripts, so a stale or broken patch fails the release instead of shipping quietly

The second is worth doing independent of this PR — the same silent-failure exposure already covers gl (^9.0.0-rc.10) and nan. sharp just makes it a third patch riding on it.

@looopmax looopmax closed this Aug 21, 2026
@looopmax looopmax reopened this Aug 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants