perf(dev): skip unchanged process-host package rebuilds (#29317)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-15 19:45:12 -07:00
committed by GitHub
co-authored by OrcaWin
parent fe08eb9a23
commit bd56d8d096
2 changed files with 38 additions and 1 deletions
@@ -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<string>()
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
@@ -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[] = []