Files
DndGamePlayer/scripts/build.mjs
T
2026-04-19 23:22:05 +08:00

104 lines
3.2 KiB
JavaScript

import { execFileSync } from 'node:child_process';
import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { build } from 'esbuild';
import { resolveIsProduction, resolveObfuscateMain } from './build-env.mjs';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const root = path.resolve(__dirname, '..');
const isProd = resolveIsProduction();
const obfuscateMain = resolveObfuscateMain();
/** База для `GET …/v1/status` (отзыв). Прод: по умолчанию публичный сервер; переопределение: `DND_LICENSE_STATUS_URL=… npm run build`. */
const DEFAULT_LICENSE_STATUS_BASE = 'https://license.mailib.ru/';
/** Старые .map от dev-сборок не должны попадать в pack. */
function removeStaleNodeBundleMaps() {
for (const p of [
path.join(root, 'dist/main/index.cjs.map'),
path.join(root, 'dist/preload/index.cjs.map'),
]) {
if (fs.existsSync(p)) fs.unlinkSync(p);
}
}
function runViteBuild() {
const cmd = isProd ? 'npx vite build' : 'npx vite build --mode development';
execFileSync(cmd, {
cwd: root,
stdio: 'inherit',
shell: true,
env: {
...process.env,
NODE_ENV: isProd ? 'production' : 'development',
},
});
}
async function buildNodeTargets() {
if (isProd) removeStaleNodeBundleMaps();
const nodeEnvLiteral = JSON.stringify(isProd ? 'production' : 'development');
const licenseStatusFromEnv = process.env.DND_LICENSE_STATUS_URL?.trim();
const licenseStatusBase =
isProd && (licenseStatusFromEnv || DEFAULT_LICENSE_STATUS_BASE)
? (licenseStatusFromEnv || DEFAULT_LICENSE_STATUS_BASE).replace(/\/+$/u, '') + '/'
: null;
const define = {
'process.env.NODE_ENV': nodeEnvLiteral,
...(licenseStatusBase
? { 'process.env.DND_LICENSE_STATUS_URL': JSON.stringify(licenseStatusBase) }
: {}),
};
const common = {
platform: 'node',
target: 'node22',
format: 'cjs',
bundle: true,
minify: isProd,
sourcemap: !isProd,
external: ['electron'],
define,
drop: isProd ? ['console', 'debugger'] : [],
};
const mainOut = path.join(root, 'dist/main/index.cjs');
await build({
...common,
entryPoints: [path.join(root, 'app/main/index.ts')],
outfile: mainOut,
});
if (isProd && obfuscateMain) {
const { obfuscateMainBundleFile } = await import('./obfuscate-main.mjs');
obfuscateMainBundleFile(mainOut);
}
await build({
...common,
entryPoints: [path.join(root, 'app/preload/index.ts')],
outfile: path.join(root, 'dist/preload/index.cjs'),
});
}
await buildNodeTargets();
execFileSync('node', [path.join(root, 'scripts', 'gen-window-icon.mjs')], {
cwd: root,
stdio: 'inherit',
});
runViteBuild();
// Тот же PNG, что electron-builder кладёт в .exe/.app — в рантайме для окна/дока (паритет с Windows).
const packIcon = path.join(root, 'build', 'icon.png');
const distPackIcon = path.join(root, 'dist', 'renderer', 'app-pack-icon.png');
if (fs.existsSync(packIcon)) {
fs.copyFileSync(packIcon, distPackIcon);
console.log('copied pack icon to', distPackIcon);
}