/**
|
* Baut aus dem gebündelten Server und der gebauten Oberfläche eine einzelne
|
* ausführbare Datei (Node SEA). Die Dateien der Oberfläche werden als Assets
|
* eingebettet und zur Laufzeit binärsicher aus der exe ausgeliefert.
|
*
|
* Voraussetzung: `npm run build` und `npm run bundle -w packages/bibliothek-server`.
|
*/
|
const { execFileSync } = require('child_process');
|
const fs = require('fs');
|
const path = require('path');
|
|
const EXE_NAME = 'Software-Bibliothek.exe';
|
const SENTINEL = 'NODE_SEA_FUSE_fce680ab2cc467b6e072b8b5df1996b2';
|
|
const wurzel = __dirname;
|
const oberflaechenOrdner = path.join(wurzel, 'packages', 'bibliothek-client', 'dist');
|
const bundleOrdner = path.join(wurzel, 'packages', 'bibliothek-server', 'build-exe');
|
const konfigPfad = path.join(bundleOrdner, 'sea-config.json');
|
const blobPfad = path.join(bundleOrdner, 'sea-prep.blob');
|
const ausgabeOrdner = path.join(wurzel, 'exe');
|
const exePfad = path.join(ausgabeOrdner, EXE_NAME);
|
|
function schritt(beschreibung, aktion) {
|
process.stdout.write(`${beschreibung} … `);
|
const ergebnis = aktion();
|
console.log(ergebnis ?? 'ok');
|
}
|
|
schritt('Oberflaechen-Dateien einsammeln', () => {
|
const dateien = fs.readdirSync(oberflaechenOrdner).filter((name) => fs.statSync(path.join(oberflaechenOrdner, name)).isFile());
|
if (!dateien.includes('index.html')) {
|
throw new Error(`In ${oberflaechenOrdner} fehlt index.html — wurde der Client gebaut?`);
|
}
|
const assets = {};
|
for (const name of dateien) {
|
assets[name] = path.relative(wurzel, path.join(oberflaechenOrdner, name)).replace(/\\/g, '/');
|
}
|
fs.writeFileSync(
|
konfigPfad,
|
JSON.stringify(
|
{
|
main: path.relative(wurzel, path.join(bundleOrdner, 'server.cjs')).replace(/\\/g, '/'),
|
output: path.relative(wurzel, blobPfad).replace(/\\/g, '/'),
|
disableExperimentalSEAWarning: true,
|
assets,
|
},
|
null,
|
2
|
)
|
);
|
return `${dateien.length} Datei(en)`;
|
});
|
|
schritt('Blob erzeugen (Server + eingebettete Oberflaeche)', () => {
|
execFileSync(process.execPath, ['--experimental-sea-config', konfigPfad], { stdio: 'pipe', cwd: wurzel });
|
});
|
|
schritt('Node-Binary kopieren', () => {
|
fs.mkdirSync(ausgabeOrdner, { recursive: true });
|
fs.copyFileSync(process.execPath, exePfad);
|
});
|
|
schritt('Code in die exe injizieren', () => {
|
execFileSync('npx', ['--yes', 'postject', exePfad, 'NODE_SEA_BLOB', blobPfad, '--sentinel-fuse', SENTINEL], {
|
stdio: 'pipe',
|
shell: process.platform === 'win32',
|
});
|
});
|
|
const groesseMb = (fs.statSync(exePfad).size / 1024 / 1024).toFixed(1);
|
console.log(`\nFertig: ${exePfad} (${groesseMb} MB)`);
|
console.log('Zum Betrieb: exe starten, dann http://localhost:3000 aufrufen.');
|
console.log('Die Nutzdaten (Datenbank + geholte Installer) landen im Ordner "data" neben der exe.');
|