mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(watcher): preserve isolation in electron-vite builds (#8162)
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import path from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { resolveWatcherProcessEntryPath } from './parcel-watcher-entry-path'
|
||||
|
||||
describe('resolveWatcherProcessEntryPath', () => {
|
||||
it('uses an adjacent entry when electron-vite appPath is already out/main', () => {
|
||||
const builtMainPath = path.join(process.cwd(), 'out', 'main')
|
||||
const adjacentEntry = path.join(builtMainPath, 'parcel-watcher-process-entry.js')
|
||||
|
||||
expect(
|
||||
resolveWatcherProcessEntryPath(
|
||||
builtMainPath,
|
||||
false,
|
||||
(candidate) => candidate === adjacentEntry
|
||||
)
|
||||
).toBe(adjacentEntry)
|
||||
})
|
||||
|
||||
it('uses the nested build entry when appPath is the project root', () => {
|
||||
expect(resolveWatcherProcessEntryPath(process.cwd(), false, () => false)).toBe(
|
||||
path.join(process.cwd(), 'out', 'main', 'parcel-watcher-process-entry.js')
|
||||
)
|
||||
})
|
||||
|
||||
it('uses the unpacked nested entry for packaged apps', () => {
|
||||
const appPath = path.join('C:', 'Orca', 'resources', 'app.asar')
|
||||
|
||||
expect(resolveWatcherProcessEntryPath(appPath, true, () => true)).toBe(
|
||||
path.join(
|
||||
'C:',
|
||||
'Orca',
|
||||
'resources',
|
||||
'app.asar.unpacked',
|
||||
'out',
|
||||
'main',
|
||||
'parcel-watcher-process-entry.js'
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,37 @@
|
||||
import { existsSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
|
||||
type ElectronAppPath = { getAppPath(): string; isPackaged: boolean }
|
||||
|
||||
function loadElectronApp(): ElectronAppPath | null {
|
||||
try {
|
||||
return require('electron').app ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function resolveWatcherProcessEntryPath(
|
||||
appPath: string,
|
||||
isPackaged: boolean,
|
||||
pathExists: (candidate: string) => boolean = existsSync
|
||||
): string {
|
||||
// Why: ELECTRON_RUN_AS_NODE bypasses Electron's asar integration, so the
|
||||
// packaged entry must be forked from app.asar.unpacked.
|
||||
const basePath = isPackaged ? appPath.replace('app.asar', 'app.asar.unpacked') : appPath
|
||||
const adjacentBuildEntry = join(basePath, 'parcel-watcher-process-entry.js')
|
||||
// Why: electron-vite's unpackaged appPath is already out/main. Appending
|
||||
// out/main again silently disables crash isolation in dev and E2E builds.
|
||||
if (!isPackaged && pathExists(adjacentBuildEntry)) {
|
||||
return adjacentBuildEntry
|
||||
}
|
||||
return join(basePath, 'out', 'main', 'parcel-watcher-process-entry.js')
|
||||
}
|
||||
|
||||
export function getWatcherProcessEntryPath(): string {
|
||||
const app = loadElectronApp()
|
||||
return resolveWatcherProcessEntryPath(
|
||||
app?.getAppPath() ?? process.cwd(),
|
||||
app?.isPackaged === true
|
||||
)
|
||||
}
|
||||
@@ -6,8 +6,8 @@
|
||||
// they can refresh state that changed during the gap.
|
||||
import { fork, type ChildProcess } from 'node:child_process'
|
||||
import { existsSync } from 'node:fs'
|
||||
import { join } from 'node:path'
|
||||
import type * as ParcelWatcher from '@parcel/watcher'
|
||||
import { getWatcherProcessEntryPath } from './parcel-watcher-entry-path'
|
||||
import type {
|
||||
HostToWatcherMessage,
|
||||
WatcherProcessEvent,
|
||||
@@ -42,23 +42,6 @@ let loggedInProcessFallback = false
|
||||
const records = new Map<number, SubscriptionRecord>()
|
||||
const pendingUnsubscribes = new Map<number, () => void>()
|
||||
|
||||
function loadElectronApp(): { getAppPath(): string; isPackaged: boolean } | null {
|
||||
try {
|
||||
return require('electron').app ?? null
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
function getWatcherProcessEntryPath(): string {
|
||||
const app = loadElectronApp()
|
||||
const appPath = app?.getAppPath() ?? process.cwd()
|
||||
// Why: ELECTRON_RUN_AS_NODE bypasses Electron's asar integration, so the
|
||||
// packaged entry must be forked from app.asar.unpacked.
|
||||
const basePath = app?.isPackaged ? appPath.replace('app.asar', 'app.asar.unpacked') : appPath
|
||||
return join(basePath, 'out', 'main', 'parcel-watcher-process-entry.js')
|
||||
}
|
||||
|
||||
function shouldRunInProcess(entryPath: string): boolean {
|
||||
// Why: vitest suites mock '@parcel/watcher' at the module level; a forked
|
||||
// child would bypass those mocks (and could execute a stale build output),
|
||||
|
||||
Reference in New Issue
Block a user