diff --git a/lib/common/mobile/windows/windows-application-manager.ts b/lib/common/mobile/windows/windows-application-manager.ts index 6b18ee393b..fc1a7925a7 100644 --- a/lib/common/mobile/windows/windows-application-manager.ts +++ b/lib/common/mobile/windows/windows-application-manager.ts @@ -10,6 +10,9 @@ import { IBuildData } from "../../../definitions/build"; export const WINDOWS_INSPECTOR_MARKER = "ns-inspector"; export const WINDOWS_DEBUGBREAK_MARKER = "ns-debugbreak"; export const WINDOWS_DEBUGGER_STARTED_MARKER = "ns-debugger-started"; +// Written by a running debug host that watches for WINDOWS_LIVESYNC_MARKER. +export const WINDOWS_LIVESYNC_READY_MARKER = "ns-livesync-ready"; +export const WINDOWS_LIVESYNC_MARKER = "ns-livesync"; export class WindowsApplicationManager extends ApplicationManagerBase { private _runningPid: number | null = null; @@ -373,6 +376,28 @@ export class WindowsApplicationManager extends ApplicationManagerBase { return this._localStatePath(pfn, fileName); } + /** + * Asks the running app to apply the files just synced into bin\app: the debug host watches + * LocalState for the marker and calls global.__onLiveSync(), which runs webpack's hot update. + * Returns false when the app's host does not watch for it (EXE targets, older runtimes). + */ + public async signalLiveSync(appId: string): Promise { + const pfn = await this._resolvePackageFamilyName(appId); + const readyPath = this._localStatePath(pfn, WINDOWS_LIVESYNC_READY_MARKER); + const markerPath = this._localStatePath(pfn, WINDOWS_LIVESYNC_MARKER); + if (!readyPath || !markerPath || !fs.existsSync(readyPath)) { + return false; + } + try { + // New content on every sync, so a marker the host has not consumed yet still changes. + fs.writeFileSync(markerPath, String(Date.now()), "utf8"); + return true; + } catch (e) { + this.$logger.trace(`[Windows] Could not write ${WINDOWS_LIVESYNC_MARKER} marker: ${e}`); + return false; + } + } + private _localStatePath(pfn: string, fileName: string): string | null { const localAppData = process.env.LOCALAPPDATA; if (!localAppData) return null; diff --git a/lib/services/livesync/windows-device-livesync-service.ts b/lib/services/livesync/windows-device-livesync-service.ts index feac8c918a..e3b040a7c9 100644 --- a/lib/services/livesync/windows-device-livesync-service.ts +++ b/lib/services/livesync/windows-device-livesync-service.ts @@ -3,6 +3,7 @@ import { spawnSync } from "child_process"; import { DeviceLiveSyncServiceBase } from "./device-livesync-service-base"; import { IPlatformsDataService } from "../../definitions/platform"; import { IProjectData } from "../../definitions/project"; +import { WindowsApplicationManager } from "../../common/mobile/windows/windows-application-manager"; export class WindowsDeviceLiveSyncService extends DeviceLiveSyncServiceBase @@ -40,22 +41,36 @@ export class WindowsDeviceLiveSyncService _projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo, ): Promise { - return !liveSyncInfo.useHotModuleReload || !!liveSyncInfo.waitForDebugger; + // A full sync (also the CLI's recovery after a failed hot update) needs a fresh start. + return ( + !liveSyncInfo.useHotModuleReload || + !!liveSyncInfo.isFullSync || + !!liveSyncInfo.waitForDebugger + ); } public async tryRefreshApplication( projectData: IProjectData, liveSyncInfo: ILiveSyncResultInfo, ): Promise { - // Vite HMR: a running app pulls every change from the dev server over its WebSocket - // (HTTP ES modules), so a synced file never needs a restart. But an app that isn't - // running yet (first sync after install) must still be launched. Webpack HMR isn't - // implemented for Windows: signal a restart. + // An app that isn't running yet (first sync after install) must still be launched. + if ( + !liveSyncInfo.useHotModuleReload || + !this.isAppRunning(projectData.projectName) + ) { + return false; + } + // Vite HMR: the app pulls every change from the dev server over its WebSocket + // (HTTP ES modules), so a synced file never needs a restart. + if (projectData.bundler === "vite") { + return true; + } + // Webpack HMR: the hot-update files are already in bin\app; tell the app to apply them. + const appId = + projectData.projectIdentifiers?.["windows"] ?? projectData.projectId; return ( - projectData.bundler === "vite" && - !!liveSyncInfo.useHotModuleReload && - this.isAppRunning(projectData.projectName) - ); + this.device.applicationManager as WindowsApplicationManager + ).signalLiveSync(appId); } private isAppRunning(processName: string): boolean {