import type { ChildProcessWithoutNullStreams } from 'node:child_process'; import { spawn } from 'node:child_process'; import { resolve } from 'node:path'; import type { BuildContext } from 'esbuild'; import * as esbuild from 'esbuild'; import kill from 'tree-kill'; import { config, electronDir, rootDir } from './common'; // this means we don't spawn electron windows, mainly for testing const watchMode = process.argv.includes('--watch'); /** Messages on stderr that match any of the contained patterns will be stripped from output */ const stderrFilterPatterns = [ // warning about devtools extension // https://github.com/cawa-93/vite-electron-builder/issues/492 // https://github.com/MarshallOfSound/electron-devtools-installer/issues/143 /ExtensionLoadWarning/, ]; let spawnProcess: ChildProcessWithoutNullStreams | null = null; function spawnOrReloadElectron() { if (watchMode) { return; } if (spawnProcess !== null && spawnProcess.pid) { spawnProcess.off('exit', process.exit); kill(spawnProcess.pid); spawnProcess = null; } const ext = process.platform === 'win32' ? '.cmd' : ''; const exe = resolve(rootDir, 'node_modules', '.bin', `electron${ext}`); spawnProcess = spawn(exe, ['.'], { cwd: electronDir, env: process.env, shell: true, }); spawnProcess.stdout.on('data', d => { const str = d.toString().trim(); if (str) { console.log(str); } }); spawnProcess.stderr.on('data', d => { const data = d.toString().trim(); if (!data) return; const mayIgnore = stderrFilterPatterns.some(r => r.test(data)); if (mayIgnore) return; console.error(data); }); // Stops the watch script when the application has quit spawnProcess.on('exit', code => { if (code && code !== 0) { console.log(`Electron exited with code ${code}`); } }); } const common = config(); async function watchLayers() { let initialBuild = false; return new Promise(resolve => { const buildContextPromise = esbuild.context({ ...common, plugins: [ ...(common.plugins ?? []), { name: 'electron-dev:reload-app-on-layers-change', setup(build) { build.onEnd(() => { if (initialBuild) { console.log(`[layers] has changed, [re]launching electron...`); spawnOrReloadElectron(); } else { buildContextPromise.then(resolve); initialBuild = true; } }); }, }, ], }); buildContextPromise.then(async buildContext => { await buildContext.watch(); }); }); } await watchLayers(); if (watchMode) { console.log(`Watching for changes...`); } else { console.log('Starting electron...'); spawnOrReloadElectron(); console.log(`Electron is started, watching for changes...`); }