Skip to content

Commit 548ba2f

Browse files
fix: replace HMR with full page reload to avoid ghost listeners and duplicate render loop
1 parent 8a1be1a commit 548ba2f

2 files changed

Lines changed: 17 additions & 5 deletions

File tree

examples/vite-starter/src/main.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,5 @@ function gameRenderPost() {
2828
}
2929

3030
// tiles.png lives in public/, served from the site root in dev and build
31+
// (on save, the vite config forces a full page reload instead of HMR)
3132
engineInit(gameInit, gameUpdate, gameUpdatePost, gameRender, gameRenderPost, ['tiles.png']);
32-
33-
// LittleJS owns global engine state (canvas, WebGL, input, RAF loop), so
34-
// partial HMR would leave ghost listeners and a duplicate render loop.
35-
// Force a full page reload on every save instead.
36-
if (import.meta.hot) import.meta.hot.accept(() => location.reload());

examples/vite-starter/vite.config.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,20 @@ export default defineConfig({
66
// (GitHub Pages project sites, itch.io uploads, etc.). Set to '/' if
77
// deploying to a domain root.
88
base: './',
9+
plugins: [
10+
{
11+
// LittleJS owns global engine state (canvas, WebGL, input, RAF
12+
// loop), so partial HMR would leave ghost listeners and a
13+
// duplicate render loop. Replace HMR with a full page reload.
14+
name: 'littlejs-full-reload',
15+
handleHotUpdate({ server, modules, timestamp }) {
16+
// invalidate manually since returning [] skips normal HMR
17+
const invalidatedModules = new Set();
18+
for (const mod of modules)
19+
server.moduleGraph.invalidateModule(mod, invalidatedModules, timestamp, true);
20+
server.ws.send({ type: 'full-reload' });
21+
return [];
22+
},
23+
},
24+
],
925
});

0 commit comments

Comments
 (0)