Merge pull request #5 from Pandipipas/create-electron-wrapper-for-scoreko-dev-l8to29

fix: document Electron module mapping and add native rebuild helper
This commit is contained in:
Pandipipas
2026-02-10 14:36:42 +01:00
committed by GitHub
4 changed files with 189 additions and 13 deletions
+13 -7
View File
@@ -42,23 +42,29 @@ cd ../..
> Si no haces `npm install` dentro de `lib/nodecg`, verás errores como `Cannot find module ... node_modules/nodecg/dist/server/bootstrap.js`.
## ¿Existe Electron con Node 22 para standalone?
## ¿Existe Electron con `NODE_MODULE_VERSION 127`?
Sí. Este proyecto usa Electron `35.x`, que permite mantener un runtime moderno y ejecutar NodeCG con el Node embebido de Electron para app standalone.
No en releases estables de Electron. Revisando la tabla oficial de releases de Electron, no aparece `modules=127`.
- Electron 32.x usa `NODE_MODULE_VERSION 128`
- Electron 34.x usa `NODE_MODULE_VERSION 132`
- Electron 35.x usa `NODE_MODULE_VERSION 133`
Por eso, para standalone hay que recompilar addons nativos contra la versión de Electron elegida.
## Error típico: NODE_MODULE_VERSION
Si ves un error como `better-sqlite3 ... NODE_MODULE_VERSION`, tienes módulos nativos compilados para una versión distinta de Node.
En ese caso recompila dentro de `lib/nodecg` con el runtime objetivo:
En ese caso recompila contra Electron:
```bash
cd lib/nodecg
npm install
npm rebuild better-sqlite3 --update-binary
npm run rebuild:native
```
Si sigues en modo standalone (default), asegúrate de no mezclar binarios compilados con otro Node fuera de tu versión de Electron.
Este script ejecuta `electron-rebuild` en `lib/nodecg` y en el workspace SQLite legacy (si existe).
Si sigues en modo standalone (default), asegúrate de no mezclar binarios compilados con otro runtime distinto al de Electron.
## Runtime de NodeCG
+126 -4
View File
@@ -12,6 +12,7 @@
"source-map-support": "^0.5.21"
},
"devDependencies": {
"@electron/rebuild": "^3.7.1",
"@types/node": "^22.10.5",
"concurrently": "^9.1.2",
"electron": "^35.7.5",
@@ -95,6 +96,88 @@
"global-agent": "^3.0.0"
}
},
"node_modules/@electron/node-gyp": {
"version": "10.2.0-electron.1",
"resolved": "git+ssh://git@github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2",
"integrity": "sha512-CrYo6TntjpoMO1SHjl5Pa/JoUsECNqNdB7Kx49WLQpWzPw53eEITJ2Hs9fh/ryUYDn4pxZz11StaBYBrLFJdqg==",
"dev": true,
"license": "MIT",
"dependencies": {
"env-paths": "^2.2.0",
"exponential-backoff": "^3.1.1",
"glob": "^8.1.0",
"graceful-fs": "^4.2.6",
"make-fetch-happen": "^10.2.1",
"nopt": "^6.0.0",
"proc-log": "^2.0.1",
"semver": "^7.3.5",
"tar": "^6.2.1",
"which": "^2.0.2"
},
"bin": {
"node-gyp": "bin/node-gyp.js"
},
"engines": {
"node": ">=12.13.0"
}
},
"node_modules/@electron/node-gyp/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@electron/node-gyp/node_modules/glob": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
"integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
"deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me",
"dev": true,
"license": "ISC",
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^5.0.1",
"once": "^1.3.0"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@electron/node-gyp/node_modules/minimatch": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
"integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@electron/node-gyp/node_modules/semver": {
"version": "7.7.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
"integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
"dev": true,
"license": "ISC",
"bin": {
"semver": "bin/semver.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/@electron/notarize": {
"version": "2.5.0",
"resolved": "https://registry.npmjs.org/@electron/notarize/-/notarize-2.5.0.tgz",
@@ -223,12 +306,13 @@
}
},
"node_modules/@electron/rebuild": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.1.tgz",
"integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==",
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.7.2.tgz",
"integrity": "sha512-19/KbIR/DAxbsCkiaGMXIdPnMCJLkcf8AvGnduJtWBs/CBwiAjY1apCqOLVxrXg+rtXFCngbXhBanWjxLUt1Mg==",
"dev": true,
"license": "MIT",
"dependencies": {
"@electron/node-gyp": "git+https://github.com/electron/node-gyp.git#06b29aafb7708acef8b3669835c8a7857ebc92d2",
"@malept/cross-spawn-promise": "^2.0.0",
"chalk": "^4.0.0",
"debug": "^4.1.1",
@@ -237,7 +321,6 @@
"got": "^11.7.0",
"node-abi": "^3.45.0",
"node-api-version": "^0.2.0",
"node-gyp": "^9.0.0",
"ora": "^5.1.0",
"read-binary-file-arch": "^1.0.6",
"semver": "^7.3.5",
@@ -1040,6 +1123,35 @@
"electron-builder-squirrel-windows": "25.1.8"
}
},
"node_modules/app-builder-lib/node_modules/@electron/rebuild": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/@electron/rebuild/-/rebuild-3.6.1.tgz",
"integrity": "sha512-f6596ZHpEq/YskUd8emYvOUne89ij8mQgjYFA5ru25QwbrRO+t1SImofdDv7kKOuWCmVOuU5tvfkbgGxIl3E/w==",
"dev": true,
"license": "MIT",
"dependencies": {
"@malept/cross-spawn-promise": "^2.0.0",
"chalk": "^4.0.0",
"debug": "^4.1.1",
"detect-libc": "^2.0.1",
"fs-extra": "^10.0.0",
"got": "^11.7.0",
"node-abi": "^3.45.0",
"node-api-version": "^0.2.0",
"node-gyp": "^9.0.0",
"ora": "^5.1.0",
"read-binary-file-arch": "^1.0.6",
"semver": "^7.3.5",
"tar": "^6.0.5",
"yargs": "^17.0.1"
},
"bin": {
"electron-rebuild": "lib/cli.js"
},
"engines": {
"node": ">=12.13.0"
}
},
"node_modules/app-builder-lib/node_modules/fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz",
@@ -4417,6 +4529,16 @@
"node": ">=10.4.0"
}
},
"node_modules/proc-log": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz",
"integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==",
"dev": true,
"license": "ISC",
"engines": {
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
}
},
"node_modules/process-nextick-args": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+4 -2
View File
@@ -14,7 +14,8 @@
"watch": "tsc -p tsconfig.json --watch",
"dev:electron": "wait-on dist/main/main.js && electron .",
"pack": "npm run build && electron-builder --dir",
"dist": "npm run build && electron-builder"
"dist": "npm run build && electron-builder",
"rebuild:native": "node scripts/rebuild-nodecg-native.mjs"
},
"build": {
"appId": "com.scoreko.desktop",
@@ -66,6 +67,7 @@
"electron-builder": "^25.1.8",
"rimraf": "^6.0.1",
"typescript": "^5.7.3",
"wait-on": "^8.0.1"
"wait-on": "^8.0.1",
"@electron/rebuild": "^3.7.1"
}
}
+46
View File
@@ -0,0 +1,46 @@
import { existsSync } from "node:fs";
import path from "node:path";
import { spawn } from "node:child_process";
const root = process.cwd();
const candidates = [
path.join(root, "lib", "nodecg"),
path.join(root, "lib", "nodecg", "workspaces", "database-adapter-sqlite-legacy"),
];
const moduleDirs = candidates.filter((dir) => existsSync(path.join(dir, "package.json")));
if (moduleDirs.length === 0) {
console.error("No NodeCG package folders found. Expected lib/nodecg and/or workspaces.");
process.exit(1);
}
function run(command, args, cwd) {
return new Promise((resolve, reject) => {
const child = spawn(command, args, {
cwd,
stdio: "inherit",
shell: process.platform === "win32",
env: {
...process.env,
npm_config_runtime: "electron",
npm_config_build_from_source: "false",
},
});
child.on("exit", (code) => {
if (code === 0) {
resolve();
} else {
reject(new Error(`${command} ${args.join(" ")} failed with code ${code}`));
}
});
});
}
for (const dir of moduleDirs) {
console.log(`\n[rebuild-native] Rebuilding native modules in: ${dir}`);
await run("npx", ["electron-rebuild", "--force", "--only", "better-sqlite3"], dir);
}
console.log("\n[rebuild-native] Done.");