mirror of
https://github.com/Pandipipas/scoreko-electron-dev.git
synced 2026-06-06 05:32:06 +00:00
41e4e91c4b
- Update .gitignore and .prettierignore to exclude additional cache and configuration files. - Revise README.md for clarity on build processes and runtime behavior. - Improve architecture documentation to reflect changes in startup flow and module responsibilities. - Modify troubleshooting guide to address common runtime issues and installation steps. - Enhance ESLint configuration to ignore more directories. - Update package.json scripts for better build and distribution processes. - Introduce build-scoreko-bundle.mjs for building the Scoreko bundle. - Implement prepare-nodecg-runtime.mjs for managing NodeCG runtime installation and updates. - Add runtime-provisioner.ts to handle user-specific NodeCG runtime provisioning. - Create tests for runtime provisioning to ensure correct behavior. - Refactor process-manager.ts and main.ts to integrate new runtime management logic.
184 lines
4.9 KiB
JavaScript
184 lines
4.9 KiB
JavaScript
#!/usr/bin/env node
|
|
import { cpSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
import path from "node:path";
|
|
import { spawnSync } from "node:child_process";
|
|
|
|
const electronRoot = process.cwd();
|
|
const bundleRoot = path.resolve(electronRoot, "..");
|
|
const runtimeRoot = path.join(electronRoot, "lib", "nodecg");
|
|
const runtimeNodeModules = path.join(runtimeRoot, "node_modules");
|
|
const bundleName = process.env.NODECG_BUNDLE_NAME?.trim() || "scoreko-dev";
|
|
const runtimeBundleRoot = path.join(runtimeRoot, "bundles", bundleName);
|
|
|
|
const bundleEntries = [
|
|
"assets",
|
|
"dashboard",
|
|
"extension",
|
|
"graphics",
|
|
"schemas",
|
|
"shared",
|
|
"configschema.json",
|
|
"LICENSE",
|
|
"package.json",
|
|
"README.md",
|
|
];
|
|
|
|
const requiredBundleEntries = ["dashboard", "extension", "graphics", "schemas", "shared", "package.json"];
|
|
|
|
function readJson(filePath) {
|
|
return JSON.parse(readFileSync(filePath, "utf8"));
|
|
}
|
|
|
|
function copyIfExists(source, destination) {
|
|
if (!existsSync(source)) {
|
|
return false;
|
|
}
|
|
|
|
cpSync(source, destination, {
|
|
recursive: true,
|
|
force: true,
|
|
dereference: true,
|
|
filter: (sourcePath) => !sourcePath.split(path.sep).includes("node_modules"),
|
|
});
|
|
return true;
|
|
}
|
|
|
|
function run(command, args, cwd) {
|
|
const result = spawnSync(command, args, {
|
|
cwd,
|
|
stdio: "inherit",
|
|
shell: process.platform === "win32",
|
|
env: {
|
|
...process.env,
|
|
npm_config_cache: process.env.npm_config_cache ?? path.join(electronRoot, ".npm-runtime-cache"),
|
|
},
|
|
});
|
|
|
|
if (result.error) {
|
|
throw new Error(`${command} ${args.join(" ")} failed: ${result.error.message}`);
|
|
}
|
|
|
|
if (result.status !== 0) {
|
|
throw new Error(`${command} ${args.join(" ")} failed with code ${result.status}`);
|
|
}
|
|
}
|
|
|
|
function getInstalledNodecgVersion() {
|
|
const nodecgPackagePath = path.join(bundleRoot, "node_modules", "nodecg", "package.json");
|
|
|
|
if (!existsSync(nodecgPackagePath)) {
|
|
throw new Error(
|
|
[
|
|
"NodeCG is not installed in the parent project.",
|
|
`Expected: ${nodecgPackagePath}`,
|
|
`Run 'pnpm install' from ${bundleRoot} before packaging.`,
|
|
].join("\n"),
|
|
);
|
|
}
|
|
|
|
return readJson(nodecgPackagePath).version;
|
|
}
|
|
|
|
function assertBundleBuildExists() {
|
|
for (const entry of requiredBundleEntries) {
|
|
const source = path.join(bundleRoot, entry);
|
|
if (!existsSync(source)) {
|
|
throw new Error(
|
|
[
|
|
`The built Scoreko bundle is missing '${entry}'.`,
|
|
`Expected: ${source}`,
|
|
`Run 'pnpm build' from ${bundleRoot} before packaging.`,
|
|
].join("\n"),
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
function createRuntimePackageJson() {
|
|
const bundlePackageJson = readJson(path.join(bundleRoot, "package.json"));
|
|
const dependencies = {
|
|
nodecg: getInstalledNodecgVersion(),
|
|
...(bundlePackageJson.dependencies ?? {}),
|
|
};
|
|
|
|
writeFileSync(
|
|
path.join(runtimeRoot, "package.json"),
|
|
`${JSON.stringify(
|
|
{
|
|
private: true,
|
|
name: "scoreko-nodecg-runtime",
|
|
version: bundlePackageJson.version ?? "0.0.0",
|
|
description: "Packaged NodeCG runtime for Scoreko Desktop.",
|
|
type: "commonjs",
|
|
scripts: {
|
|
start: "node index.js",
|
|
},
|
|
dependencies,
|
|
},
|
|
null,
|
|
2,
|
|
)}\n`,
|
|
);
|
|
|
|
writeFileSync(path.join(runtimeRoot, "index.js"), 'require("nodecg");\n');
|
|
}
|
|
|
|
function copyBundle() {
|
|
mkdirSync(runtimeBundleRoot, { recursive: true });
|
|
|
|
for (const entry of bundleEntries) {
|
|
copyIfExists(path.join(bundleRoot, entry), path.join(runtimeBundleRoot, entry));
|
|
}
|
|
}
|
|
|
|
function writeManifest() {
|
|
const bundlePackageJson = readJson(path.join(bundleRoot, "package.json"));
|
|
const runtimePackageJson = readJson(path.join(runtimeRoot, "package.json"));
|
|
|
|
writeFileSync(
|
|
path.join(runtimeRoot, ".scoreko-runtime.json"),
|
|
`${JSON.stringify(
|
|
{
|
|
bundleName,
|
|
bundleVersion: bundlePackageJson.version ?? "0.0.0",
|
|
nodecgVersion: runtimePackageJson.dependencies.nodecg,
|
|
generatedAt: new Date().toISOString(),
|
|
},
|
|
null,
|
|
2,
|
|
)}\n`,
|
|
);
|
|
}
|
|
|
|
function installRuntimeDependencies() {
|
|
if (process.env.SCOREKO_SKIP_RUNTIME_NPM_INSTALL === "1") {
|
|
console.log("[prepare-runtime] Skipping runtime npm install by environment request.");
|
|
return;
|
|
}
|
|
|
|
const npmCommand = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
run(npmCommand, ["install", "--omit=dev", "--no-audit", "--no-fund"], runtimeRoot);
|
|
}
|
|
|
|
function main() {
|
|
assertBundleBuildExists();
|
|
|
|
rmSync(runtimeRoot, { recursive: true, force: true });
|
|
mkdirSync(runtimeNodeModules, { recursive: true });
|
|
mkdirSync(path.join(runtimeRoot, "bundles"), { recursive: true });
|
|
|
|
createRuntimePackageJson();
|
|
copyBundle();
|
|
installRuntimeDependencies();
|
|
writeManifest();
|
|
|
|
console.log(`[prepare-runtime] NodeCG runtime ready at ${runtimeRoot}`);
|
|
}
|
|
|
|
try {
|
|
main();
|
|
} catch (error) {
|
|
console.error(error instanceof Error ? error.message : error);
|
|
process.exit(1);
|
|
}
|