PURPOSE
Dev-only React component that intercepts Vite HMR-triggered full-page reloads in the playground screen. Instead of letting the page silently refresh, it surfaces a clickable badge so the developer chooses when to reload, preserving in-memory playground state across HMR cycles.
OWNS
- A module-level reload-block state (
_originalReload,_blocked) that survives HMR re-renders of the component itself. - The override of
Location.prototype.reloadfor the lifetime of the component (installed on mount, removed on unmount). - A
pendinglocal React state flag indicating that a reload was attempted and is being held. - The
BADGEstyle object and the floating amber button rendered in the top-right corner when a reload is pending.
READS FROM
import.meta.env.DEV— gates the entire behavior to development builds; production renders nothing and never installs the override.import.meta.hot— when available, subscribes to Vite’svite:beforeFullReloadevent as a secondary trigger.Location.prototype.reload— read once on install to capture the original reload function for later restoration and explicit invocation.
PUSHES TO
Location.prototype— replacesreloadwith a guarded version viaObject.definePropertyand restores the original on cleanup.window— dispatches apg:reload-blockedCustomEventwhenever a reload call is intercepted while the block is active.- Local React state — flips
pendingtotruewhen either the custom event fires or Vite’svite:beforeFullReloadhook fires. window.location(via the captured originalreload) when the developer clicks the badge to actually perform the reload.
DOES NOT
- Does not affect production builds; both the effect and the render bail out when
import.meta.env.DEVis false. - Does not block reloads triggered outside
location.reload()(e.g., explicitlocation.hrefassignment, anchor navigation, browser refresh button). - Does not persist
pendingacross remounts or page loads; it is purely in-memory React state. - Does not coordinate with other guards or screens; the override is global to the page once installed, but the badge UI is local to this component.
- Does not log, telemeter, or otherwise report blocked reloads.
Signals
- Event listened to:
pg:reload-blockedonwindow. - Event emitted:
pg:reload-blockedonwindow(viaCustomEvent), dispatched from inside the patchedreload. - Vite HMR hook:
vite:beforeFullReloadviaimport.meta.hot.on. - Return value of
installReloadBlockindicates whether the browser permitted the prototype override; failure is swallowed and the component renders nothing.
Entry points
PlaygroundUpdateGuard— named export, the React component. Mounted once inside the playground screen tree.installReloadBlock/removeReloadBlock— internal helpers; not exported.
Pattern notes
- Module-level (not component-level) state is used so HMR replacing the component module does not lose the override or leak duplicate patches.
- Idempotent install:
installReloadBlockearly-returns when_blockedis already set. - Belt-and-suspenders: both the prototype override and the Vite
vite:beforeFullReloadhook can independently setpending, covering paths where Vite reloads via mechanisms other thanlocation.reload(). - Cleanup restores the original
reloadand removes the listener, so unmounting the component returns the page to default browser behavior. - The override uses
Object.definePropertywithconfigurable: trueso a subsequent restore (or another patch) can replace it cleanly. - Failure to override (some browser sandboxes refuse) is silently tolerated — the component simply renders nothing.