()
| 804 | } catch {} |
| 805 | |
| 806 | async function processQueue() { |
| 807 | if (!(globalThis as any).__NS_HMR_BOOT_COMPLETE__) { |
| 808 | if (VERBOSE) console.log('[hmr][gate] deferring HMR eval until boot complete'); |
| 809 | setTimeout(() => { |
| 810 | try { |
| 811 | processQueue(); |
| 812 | } catch {} |
| 813 | }, 150); |
| 814 | return; |
| 815 | } |
| 816 | if (processingQueue) return; |
| 817 | processingQueue = true; |
| 818 | try { |
| 819 | // Simple deterministic drain of the queue. We currently focus on TS flavor |
| 820 | // by re-importing changed modules (to refresh their HTTP ESM copies) and |
| 821 | // then performing a root reset so the UI reflects the new code. |
| 822 | const seen = new Set<string>(); |
| 823 | const drained: string[] = []; |
| 824 | while (changedQueue.length) { |
| 825 | const id = changedQueue.shift(); |
| 826 | if (!id || typeof id !== 'string') continue; |
| 827 | if (seen.has(id)) continue; |
| 828 | seen.add(id); |
| 829 | drained.push(id); |
| 830 | } |
| 831 | if (!drained.length) return; |
| 832 | if (VERBOSE) console.log('[hmr][queue] processing changed ids', drained); |
| 833 | // Evaluate changed modules best-effort; failures shouldn't completely break HMR. |
| 834 | for (const id of drained) { |
| 835 | try { |
| 836 | const spec = normalizeSpec(id); |
| 837 | const url = await requestModuleFromServer(spec); |
| 838 | if (!url) continue; |
| 839 | if (VERBOSE) console.log('[hmr][queue] re-import', { id, spec, url }); |
| 840 | await import(/* @vite-ignore */ url); |
| 841 | } catch (e) { |
| 842 | if (VERBOSE) console.warn('[hmr][queue] re-import failed for', id, e); |
| 843 | } |
| 844 | } |
| 845 | // After evaluating the batch, perform flavor-specific UI refresh. |
| 846 | switch (__NS_TARGET_FLAVOR__) { |
| 847 | case 'vue': |
| 848 | // Vue SFCs are handled via the registry update path; nothing to do here. |
| 849 | break; |
| 850 | case 'typescript': { |
| 851 | // For TS apps, always reset back to the conventional app root. |
| 852 | // This preserves the shell (Frame, ActionBar, etc.) that the app's |
| 853 | // own bootstrapping wires up via `Application.run`. |
| 854 | try { |
| 855 | const g: any = globalThis as any; |
| 856 | const App = getCore('Application') || g.Application; |
| 857 | if (!App || typeof App.resetRootView !== 'function') { |
| 858 | if (VERBOSE) console.warn('[hmr][queue] TS flavor: Application.resetRootView unavailable; skipping UI refresh'); |
| 859 | break; |
| 860 | } |
| 861 | if (VERBOSE) console.log('[hmr][queue] TS flavor: resetRootView(app-root) after changes'); |
| 862 | App.resetRootView({ moduleName: 'app-root' } as any); |
| 863 | } catch (e) { |
no test coverage detected