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); }