Skip to content

Commit 4c1ce4f

Browse files
authored
Merge pull request #32 from NativeScript/feat/webpack-hmr-livesync
feat: apply webpack HMR updates while a debug app runs
2 parents 4ad1bf2 + 7d49623 commit 4c1ce4f

2 files changed

Lines changed: 59 additions & 0 deletions

File tree

‎template/framework/__PROJECT_NAME__/App.xaml.cs‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ protected override async void OnLaunched(LaunchActivatedEventArgs e)
9898
void ShowMainWindow()
9999
{
100100
StartPump();
101+
#if DEBUG
102+
_runtimeHost.WatchLiveSync(DispatcherQueue.GetForCurrentThread());
103+
#endif
101104

102105
try
103106
{

‎template/framework/__PROJECT_NAME__/RuntimeHost.cs‎

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,60 @@ public void PumpTimers()
123123
private const string InspectorMarker = "ns-inspector";
124124
private const string DebugBreakMarker = "ns-debugbreak";
125125
private const string DebuggerStartedMarker = "ns-debugger-started";
126+
// The CLI writes LiveSyncMarker after syncing files into app\ (webpack HMR), but only
127+
// while LiveSyncReadyMarker says this host is watching for it.
128+
private const string LiveSyncMarker = "ns-livesync";
129+
private const string LiveSyncReadyMarker = "ns-livesync-ready";
126130

127131
private bool _waitForDebugger;
132+
private FileSystemWatcher _liveSyncWatcher;
133+
134+
/// Applies CLI file syncs while the app runs, by calling global.__onLiveSync() on the UI
135+
/// thread, as the Android and iOS runtimes do after a LiveSync.
136+
public void WatchLiveSync(Microsoft.UI.Dispatching.DispatcherQueue dispatcherQueue)
137+
{
138+
if (!_initialized || _liveSyncWatcher != null || dispatcherQueue == null) return;
139+
try
140+
{
141+
DeleteMarker(LiveSyncMarker);
142+
var watcher = new FileSystemWatcher(LocalFolderPath, LiveSyncMarker)
143+
{
144+
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
145+
};
146+
FileSystemEventHandler onMarker = (_, _) => dispatcherQueue.TryEnqueue(ApplyLiveSync);
147+
watcher.Created += onMarker;
148+
watcher.Changed += onMarker;
149+
watcher.EnableRaisingEvents = true;
150+
_liveSyncWatcher = watcher;
151+
WriteMarker(LiveSyncReadyMarker, "");
152+
}
153+
catch (Exception ex)
154+
{
155+
System.Diagnostics.Debug.WriteLine($"[NativeScript LiveSync] Watch failed: {ex.Message}");
156+
}
157+
}
158+
159+
private void ApplyLiveSync()
160+
{
161+
// One write raises several events; the first one consumes the marker.
162+
if (!_initialized || !ConsumeMarker(LiveSyncMarker)) return;
163+
try
164+
{
165+
runtime_runscript(_runtime, "typeof __onLiveSync === 'function' && __onLiveSync();", "ns-livesync.js");
166+
}
167+
catch (Exception ex)
168+
{
169+
System.Diagnostics.Debug.WriteLine($"[NativeScript LiveSync] Apply failed: {ex.Message}");
170+
}
171+
}
172+
173+
private void StopWatchingLiveSync()
174+
{
175+
if (_liveSyncWatcher == null) return;
176+
_liveSyncWatcher.Dispose();
177+
_liveSyncWatcher = null;
178+
DeleteMarker(LiveSyncReadyMarker);
179+
}
128180

129181
public string DevtoolsFrontendUrl { get; private set; }
130182

@@ -235,6 +287,7 @@ public void Initialize()
235287
}
236288
catch { }
237289
DeleteMarker(DebuggerStartedMarker);
290+
DeleteMarker(LiveSyncReadyMarker);
238291
var debugBreak = ConsumeMarker(DebugBreakMarker);
239292
if (ConsumeMarker(InspectorMarker) || debugBreak)
240293
{
@@ -476,6 +529,9 @@ public string GetLastJsError()
476529
public void Dispose()
477530
{
478531
if (!_initialized) return;
532+
#if DEBUG
533+
StopWatchingLiveSync();
534+
#endif
479535
runtime_deinit(_runtime);
480536
_runtime = 0;
481537
_initialized = false;

0 commit comments

Comments
 (0)