From bd56d8d096328db8bc093bd290bad4f21ee3c0cd Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Thu, 15 Oct 2026 19:45:12 -0700 Subject: [PATCH] perf(dev): skip unchanged process-host package rebuilds (#29317) Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- .../build-plugins/process-host-dev-rebuild.ts | 14 +++++++++++ .../scripts/process-host-dev-rebuild.test.ts | 25 ++++++++++++++++++- 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/config/build-plugins/process-host-dev-rebuild.ts b/config/build-plugins/process-host-dev-rebuild.ts index cf7bf0b6590..c9666f4fc56 100644 --- a/config/build-plugins/process-host-dev-rebuild.ts +++ b/config/build-plugins/process-host-dev-rebuild.ts @@ -49,13 +49,22 @@ export function createProcessHostDevRebuildPlugin(root = process.cwd()): Plugin let signalDirectory: string | undefined let signalFile: string | undefined let signalVersion = 0 + let packageDirty = true + let packageFiles = new Set() return { name: 'orca-process-host-dev-rebuild', + watchChange(id) { + const file = resolve(id) + if (packageFiles.has(file) || file === signalFile) { + packageDirty = true + } + }, buildStart() { if (!this.meta.watchMode) { return } const inputs = processHostInputs(root) + packageFiles = new Set(inputs.files.map((file) => resolve(file))) for (const file of inputs.files) { this.addWatchFile(file) } @@ -87,6 +96,7 @@ export function createProcessHostDevRebuildPlugin(root = process.cwd()): Plugin const watcher = ts.sys.watchDirectory( directory, () => { + packageDirty = true if (signalFile) { writeFileSync(signalFile, String(++signalVersion)) } @@ -96,6 +106,9 @@ export function createProcessHostDevRebuildPlugin(root = process.cwd()): Plugin ) directoryWatchers.set(directory, { recursive, watcher }) } + if (!packageDirty) { + return + } // The external package must finish emitting before electron-vite restarts the app. The // package's own build keeps its compiler and per-file atomic dist sync identical to build:packages. const result = runProcessSync({ @@ -113,6 +126,7 @@ export function createProcessHostDevRebuildPlugin(root = process.cwd()): Plugin `[process-host-dev-rebuild] Package compilation failed: ${result.stderr || result.stdout || result.signal || result.code}` ) } + packageDirty = false }, closeWatcher() { signalFile = undefined diff --git a/config/scripts/process-host-dev-rebuild.test.ts b/config/scripts/process-host-dev-rebuild.test.ts index f732451beef..e02db947e13 100644 --- a/config/scripts/process-host-dev-rebuild.test.ts +++ b/config/scripts/process-host-dev-rebuild.test.ts @@ -38,7 +38,7 @@ function fixture(): { root: string; packageDir: string; main: string } { // Runs the real package build against this fixture package. writeFileSync( join(packageDir, 'scripts', 'build-dist.mjs'), - `const { buildPackageDist } = await import(${JSON.stringify(pathToFileURL(resolve(realPackageDir, 'scripts', 'build-dist.mjs')).href)})\nawait buildPackageDist(${JSON.stringify(packageDir)})\n` + `import { appendFileSync } from 'node:fs'\nappendFileSync(${JSON.stringify(join(packageDir, 'builds.txt'))}, 'build\\n')\nconst { buildPackageDist } = await import(${JSON.stringify(pathToFileURL(resolve(realPackageDir, 'scripts', 'build-dist.mjs')).href)})\nawait buildPackageDist(${JSON.stringify(packageDir)})\n` ) mkdirSync(join(root, 'node_modules', '@orca'), { recursive: true }) const packageRequire = createRequire(join(realPackageDir, 'package.json')) @@ -127,6 +127,29 @@ function readEmittedVersion(root: string): number { } describe('External process-host development rebuilds', () => { + it('skips package compilation when only application code changes', async () => { + const { root, packageDir, main } = fixture() + const watcher = watch({ + input: main, + external: ['@orca/process-host'], + plugins: [createProcessHostDevRebuildPlugin(root)], + output: { file: join(root, 'out', 'main.cjs'), format: 'cjs' } + }) + watchers.push(watcher) + closeSuccessfulBundles(watcher) + await nextEvent(watcher, 'END') + const builds = join(packageDir, 'builds.txt') + expect(readFileSync(builds, 'utf8')).toBe('build\n') + + const rebuilt = nextEvent(watcher, 'END') + writeFileSync(main, "module.exports = { ...require('@orca/process-host'), changed: true }\n") + await rebuilt + + expect(readEmittedVersion(root)).toBe(1) + expect(readFileSync(join(root, 'out', 'main.cjs'), 'utf8')).toContain('changed') + expect(readFileSync(builds, 'utf8')).toBe('build\n') + }) + it('emits private source edits and new imports before the Electron reload hook', async () => { const { root, packageDir, main } = fixture() const loadedVersions: number[] = []