cindel 1.0.5 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +49 -9
- package/dist/client/file-loader.d.ts +2 -2
- package/dist/client/file-loader.d.ts.map +1 -1
- package/dist/client/hmr-client.d.ts.map +1 -1
- package/dist/client/stub.d.ts.map +1 -1
- package/dist/client.iife.js +112 -49
- package/dist/client.iife.js.map +3 -3
- package/dist/client.iife.min.js +4 -1
- package/dist/client.iife.min.js.map +3 -3
- package/dist/client.js +112 -49
- package/dist/client.js.map +3 -3
- package/dist/index.js +27 -4
- package/dist/index.js.map +3 -3
- package/dist/server/hmr-server.d.ts +16 -0
- package/dist/server/hmr-server.d.ts.map +1 -1
- package/dist/server/routes.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,16 +23,17 @@
|
|
|
23
23
|
- HTTP CORS proxy with configurable header injection
|
|
24
24
|
- WebSocket proxy with header forwarding and message interception
|
|
25
25
|
- Static file server and automatic `index.html` loader injection
|
|
26
|
+
- Custom route handlers and directory mirroring via Bun's native routing
|
|
26
27
|
- TLS/HTTPS + WSS support
|
|
27
28
|
- `/files` endpoint exposing the live watched file list as JSON
|
|
28
29
|
|
|
29
30
|
**Client**
|
|
30
31
|
|
|
32
|
+
- No runtime dependencies, works in any modern browser
|
|
31
33
|
- Exponential backoff with automatic reconnect
|
|
32
|
-
- No runtime dependencies, so it works in any modern browser
|
|
33
34
|
- Event system with `on`, `once`, and `off` for connect, disconnect, reload, add, remove, etc.
|
|
34
|
-
- IIFE build compatible with userscript managers (Tampermonkey, Greasemonkey) via `@require`
|
|
35
35
|
- Iframe injection via `postMessage` for Private Network Access restricted environments
|
|
36
|
+
- IIFE build compatible with userscript managers (Tampermonkey, Greasemonkey) via `@require`
|
|
36
37
|
|
|
37
38
|
---
|
|
38
39
|
|
|
@@ -140,8 +141,10 @@ You can even load it through a user script on any domain:
|
|
|
140
141
|
| `static` | `string \| false` | `'.'` | Directory to serve static files from. Pass `false` to disable static serving |
|
|
141
142
|
| `indexPath` | `string` | `'index.html'` | Path to `index.html` |
|
|
142
143
|
| `injectLoader` | `string` | | Script path injected into `index.html` before `</head>` |
|
|
144
|
+
| `injectPaths` | `Array<string\|{path: string, html: string}>` | `['/']` | Paths where the loader script is injected |
|
|
143
145
|
| `corsProxy` | `boolean \| string\| CORSProxyConfig` | | Enable the HTTP CORS proxy |
|
|
144
146
|
| `wsProxy` | `WSProxyConfig` | | Proxy WebSocket connections to an upstream server |
|
|
147
|
+
| `routes` | `Object` | | Custom routes passed directly to `Bun.serve` |
|
|
145
148
|
| `filesEndpoint` | `boolean \| string` | `'/files'` | Expose the watched file list as JSON. `true` mounts at `/files` |
|
|
146
149
|
| `configEndpoint` | `boolean \| string` | `'/config'` | Expose the server config as JSON. `false` to disable |
|
|
147
150
|
| `getFiles` | `() => string[]` | | Override the file list sent to connecting clients |
|
|
@@ -262,6 +265,43 @@ new HMRServer({
|
|
|
262
265
|
|
|
263
266
|
---
|
|
264
267
|
|
|
268
|
+
### Routing
|
|
269
|
+
|
|
270
|
+
The `routes` option is passed directly to `Bun.serve`. Useful for mocking APIs, serving specific files, or mirroring directories without a separate server process. See [Bun's routing docs](https://bun.sh/docs/api/http#routing) for the full API.
|
|
271
|
+
|
|
272
|
+
```js
|
|
273
|
+
routes: {
|
|
274
|
+
// Serve a specific file
|
|
275
|
+
'/favicon.ico': new Response(Bun.file('./public/favicon.ico')),
|
|
276
|
+
|
|
277
|
+
// Mock API responses
|
|
278
|
+
'/api/session': Response.json({ user: 'dev', role: 'admin' }),
|
|
279
|
+
'/api/flags': Response.json({ darkMode: true, betaFeatures: false }),
|
|
280
|
+
|
|
281
|
+
// Named params
|
|
282
|
+
'/api/users/:id': req => Response.json({ id: req.params.id }),
|
|
283
|
+
|
|
284
|
+
// Per-method handlers
|
|
285
|
+
'/api/posts': {
|
|
286
|
+
GET: () => new Response("List posts"),
|
|
287
|
+
POST: async req => {
|
|
288
|
+
const body = await req.json();
|
|
289
|
+
return Response.json({ created: true, ...body });
|
|
290
|
+
},
|
|
291
|
+
},
|
|
292
|
+
|
|
293
|
+
// Mirror directory /assets/* served from /dist/assets/*
|
|
294
|
+
'/assets/*': req => new Response(Bun.file(`./dist/assets/${req.params['*']}`)),
|
|
295
|
+
|
|
296
|
+
// SPA fallback
|
|
297
|
+
'/*': new Response(Bun.file('./index.html')),
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
> **Note:** Avoid paths that overlap with `wsPath`, `filesEndpoint`, `configEndpoint`, or any proxy paths, the server will warn on startup if a collision is detected.
|
|
302
|
+
|
|
303
|
+
---
|
|
304
|
+
|
|
265
305
|
### TLS
|
|
266
306
|
|
|
267
307
|
Pass `tls` to switch the server to HTTPS and WSS. The client's `secure` option or a `wss://` URL flips the client to match.
|
|
@@ -442,14 +482,14 @@ client
|
|
|
442
482
|
console.log(`Loaded ${files.length} files`);
|
|
443
483
|
console.log("Server cold patterns:", config.cold);
|
|
444
484
|
})
|
|
445
|
-
.on("reload", (
|
|
485
|
+
.on("reload", (file) => {
|
|
446
486
|
console.log(`Hot-reloaded: ${file}`);
|
|
447
|
-
|
|
487
|
+
swapPrototype(file);
|
|
448
488
|
})
|
|
449
|
-
.on("add", (
|
|
489
|
+
.on("add", (file) => {
|
|
450
490
|
console.log(`New file available: ${file}`);
|
|
451
491
|
})
|
|
452
|
-
.on("remove", (
|
|
492
|
+
.on("remove", (file) => {
|
|
453
493
|
console.log(`File removed: ${file}`);
|
|
454
494
|
cleanupForFile(file);
|
|
455
495
|
})
|
|
@@ -467,9 +507,9 @@ client
|
|
|
467
507
|
| `connect` | | WebSocket connection established |
|
|
468
508
|
| `disconnect` | | WebSocket disconnected |
|
|
469
509
|
| `init` | `{ files, config }` | Server sent the initial file list |
|
|
470
|
-
| `reload` | `
|
|
471
|
-
| `add` | `
|
|
472
|
-
| `remove` | `
|
|
510
|
+
| `reload` | `file: string` | A file was changed and hot-reloaded |
|
|
511
|
+
| `add` | `file: string` | A new file was detected |
|
|
512
|
+
| `remove` | `file: string` | A file was removed |
|
|
473
513
|
| `cold` | `file: string` | A cold file changed |
|
|
474
514
|
| `error` | `Error` | A connection or message error occurred |
|
|
475
515
|
|
|
@@ -49,7 +49,7 @@ export class FileLoader {
|
|
|
49
49
|
_flushReload(path: any): Promise<void>;
|
|
50
50
|
removeFile(path: any): Promise<void>;
|
|
51
51
|
makeUrl(path: any): string;
|
|
52
|
-
|
|
53
|
-
_inject(kind: any, code: any, file: any):
|
|
52
|
+
_postAndAwaitAck(message: any): Promise<any>;
|
|
53
|
+
_inject(kind: any, code: any, file: any): Promise<any>;
|
|
54
54
|
}
|
|
55
55
|
//# sourceMappingURL=file-loader.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file-loader.d.ts","sourceRoot":"","sources":["../../src/client/file-loader.js"],"names":[],"mappings":"AAAA,mFAAmF;AACnF;IACE;;;;OAiCC;IAhCC,aAAsB;IACtB;;;;;OAKG;IACH,cAFU,MAAM,GAAG,IAAI,CAES;IAChC,qBAAqB;IACrB,cADW,MAAM,CACe;IAChC;;;;;;OAMG;IACH,KAFU,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAExB;IACd;;;;;OAKG;IACH,WAFU,GAAG,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,UAAU,CAAA;KAAE,CAAC,CAEvC;IAC1B;;;;;OAKG;IACH,UAFU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAEJ;IAG3B,kCAOC;IAKD,qCAwBC;IAED,oDAmBC;IAED,wCAcC;IAED,
|
|
1
|
+
{"version":3,"file":"file-loader.d.ts","sourceRoot":"","sources":["../../src/client/file-loader.js"],"names":[],"mappings":"AAAA,mFAAmF;AACnF;IACE;;;;OAiCC;IAhCC,aAAsB;IACtB;;;;;OAKG;IACH,cAFU,MAAM,GAAG,IAAI,CAES;IAChC,qBAAqB;IACrB,cADW,MAAM,CACe;IAChC;;;;;;OAMG;IACH,KAFU,QAAQ,GAAG,QAAQ,GAAG,MAAM,CAExB;IACd;;;;;OAKG;IACH,WAFU,GAAG,CAAC,MAAM,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,UAAU,CAAA;KAAE,CAAC,CAEvC;IAC1B;;;;;OAKG;IACH,UAFU,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAEJ;IAG3B,kCAOC;IAKD,qCAwBC;IAED,oDAmBC;IAED,wCAcC;IAED,oCA4BC;IAKD,oCAeC;IAED,uCAUC;IAED,qCAqBC;IAGD,2BAIC;IAED,6CAaC;IAED,uDAEC;CACF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hmr-client.d.ts","sourceRoot":"","sources":["../../src/client/hmr-client.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;IACE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,qBAvBG;QAAyB,KAAK,GAAtB,MAAM;QACW,OAAO,GAAxB,MAAM;QACY,UAAU,GAA5B,OAAO;QACU,IAAI,GAArB,MAAM;QACW,IAAI,GAArB,MAAM;QACY,MAAM,GAAxB,OAAO;QACW,aAAa,GAA/B,OAAO;QACU,cAAc,GAA/B,MAAM;QACW,iBAAiB,GAAlC,MAAM;QACY,eAAe,GAAjC,OAAO;QACY,IAAI,GAAvB,MAAM,EAAE;QACsC,UAAU,GAAxD,CAAS,IAAM,EAAN,MAAM,EAAE,IAAQ,EAAR,MAAM,EAAE,KAAG,OAAO;QAChB,IAAI,GAAvB,MAAM,EAAE;QAC4B,UAAU,GAA9C,CAAS,IAAM,EAAN,MAAM,KAAG,OAAO;QACyB,iBAAiB,GAAnE,CAAS,IAAM,EAAN,MAAM,EAAE,IAAQ,EAAR,MAAM,EAAE,KAAG,MAAM,GAAC,IAAI;QACN,YAAY,GAA7C,CAAS,IAAM,EAAN,MAAM,KAAG,IAAI;QACiB,SAAS,GAAhD,CAAS,IAAQ,EAAR,MAAM,EAAE,KAAG,MAAM,EAAE;QACF,SAAS,GAAnC,KAAK,UAAU;QACY,MAAM,GAAjC,OAAO,MAAS;KACxB,EAwFF;IA9EC,WAAkB;IAClB,aAAsB;IACtB,oBAAsB;IAEtB,+BAAyD;IACzD,uBAA+C;IAC/C,uBAAiD;IACjD,0BAAwD;IACxD,yBAAqD;IAGrD,wBAAsC;IACtC,oBA5BkB,MAAM,KAAG,OAAO,CA4BQ;IAG1C,oBAAiF;IACjF,gBAAuE;IAGvE,gBAAkB;IAElB,0BApCkB,MAAM,QAAE,MAAM,EAAE,KAAG,MAAM,GAAC,IAAI,CAoCO;IACvD,qBApCkB,MAAM,KAAG,IAAI,CAoCc;IAC7C,sBAAqC;IACrC,eAAmE;IAEnE,kBAAkB;IAClB,0BAA0B;IAC1B,qBAAwB;IACxB,6BAA8B;IAC9B,gCAA2B;IAI3B,qBAAuB;IACvB,6BAAgC;IAShC,mBAAiC;IACjC,mBAAiC;IAIjC,sBAAiD;IAGjD,uCAAuB;IAEvB,uBAIE;IAEF,wEAAwE;IACxE,aADW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CACF;IAC5B,uFAAuF;IACvF,qBADW,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CACC;IAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAYC;IAGH,oCAkBC;IAED,8CAcC;IAED,mCAIC;IAED,sEAoDC;IAED,kCA0BC;IAED,4CAgDC;IAED,8EAkEC;IAED,2CA4CC;IAED,wCA6CC;IAED;;;;;OAKG;IACH,UAJW,MAAM,GAAC,QAAQ,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,SAAS,GAAC,YAAY,GAAC,OAAO,sBAElE,SAAS,CAQrB;IAED;;;;;OAKG;IACH,YAJW,MAAM,GAAC,QAAQ,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,SAAS,GAAC,YAAY,GAAC,OAAO,sBAElE,SAAS,CASrB;IAED;;;;;OAKG;IACH,WAJW,MAAM,GAAC,QAAQ,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,SAAS,GAAC,YAAY,GAAC,OAAO,sBAElE,SAAS,CAoBrB;IAED,uCAQC;IAMD,iCAGC;IAED,oCAWC;IAID,
|
|
1
|
+
{"version":3,"file":"hmr-client.d.ts","sourceRoot":"","sources":["../../src/client/hmr-client.js"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH;IACE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA6BG;IACH,qBAvBG;QAAyB,KAAK,GAAtB,MAAM;QACW,OAAO,GAAxB,MAAM;QACY,UAAU,GAA5B,OAAO;QACU,IAAI,GAArB,MAAM;QACW,IAAI,GAArB,MAAM;QACY,MAAM,GAAxB,OAAO;QACW,aAAa,GAA/B,OAAO;QACU,cAAc,GAA/B,MAAM;QACW,iBAAiB,GAAlC,MAAM;QACY,eAAe,GAAjC,OAAO;QACY,IAAI,GAAvB,MAAM,EAAE;QACsC,UAAU,GAAxD,CAAS,IAAM,EAAN,MAAM,EAAE,IAAQ,EAAR,MAAM,EAAE,KAAG,OAAO;QAChB,IAAI,GAAvB,MAAM,EAAE;QAC4B,UAAU,GAA9C,CAAS,IAAM,EAAN,MAAM,KAAG,OAAO;QACyB,iBAAiB,GAAnE,CAAS,IAAM,EAAN,MAAM,EAAE,IAAQ,EAAR,MAAM,EAAE,KAAG,MAAM,GAAC,IAAI;QACN,YAAY,GAA7C,CAAS,IAAM,EAAN,MAAM,KAAG,IAAI;QACiB,SAAS,GAAhD,CAAS,IAAQ,EAAR,MAAM,EAAE,KAAG,MAAM,EAAE;QACF,SAAS,GAAnC,KAAK,UAAU;QACY,MAAM,GAAjC,OAAO,MAAS;KACxB,EAwFF;IA9EC,WAAkB;IAClB,aAAsB;IACtB,oBAAsB;IAEtB,+BAAyD;IACzD,uBAA+C;IAC/C,uBAAiD;IACjD,0BAAwD;IACxD,yBAAqD;IAGrD,wBAAsC;IACtC,oBA5BkB,MAAM,KAAG,OAAO,CA4BQ;IAG1C,oBAAiF;IACjF,gBAAuE;IAGvE,gBAAkB;IAElB,0BApCkB,MAAM,QAAE,MAAM,EAAE,KAAG,MAAM,GAAC,IAAI,CAoCO;IACvD,qBApCkB,MAAM,KAAG,IAAI,CAoCc;IAC7C,sBAAqC;IACrC,eAAmE;IAEnE,kBAAkB;IAClB,0BAA0B;IAC1B,qBAAwB;IACxB,6BAA8B;IAC9B,gCAA2B;IAI3B,qBAAuB;IACvB,6BAAgC;IAShC,mBAAiC;IACjC,mBAAiC;IAIjC,sBAAiD;IAGjD,uCAAuB;IAEvB,uBAIE;IAEF,wEAAwE;IACxE,aADW,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CACF;IAC5B,uFAAuF;IACvF,qBADW,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CACC;IAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;MAYC;IAGH,oCAkBC;IAED,8CAcC;IAED,mCAIC;IAED,sEAoDC;IAED,kCA0BC;IAED,4CAgDC;IAED,8EAkEC;IAED,2CA4CC;IAED,wCA6CC;IAED;;;;;OAKG;IACH,UAJW,MAAM,GAAC,QAAQ,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,SAAS,GAAC,YAAY,GAAC,OAAO,sBAElE,SAAS,CAQrB;IAED;;;;;OAKG;IACH,YAJW,MAAM,GAAC,QAAQ,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,SAAS,GAAC,YAAY,GAAC,OAAO,sBAElE,SAAS,CASrB;IAED;;;;;OAKG;IACH,WAJW,MAAM,GAAC,QAAQ,GAAC,KAAK,GAAC,QAAQ,GAAC,MAAM,GAAC,SAAS,GAAC,YAAY,GAAC,OAAO,sBAElE,SAAS,CAoBrB;IAED,uCAQC;IAMD,iCAGC;IAED,oCAWC;IAID,6BAyBC;IAKD,2BA0BC;IAED;;;OAGG;IACH,WAFa,OAAO,CAAC,IAAI,CAAC,CAiGzB;IAED;;OAEG;IACH,mBAgBC;CACF;2BA5uB0B,kBAAkB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stub.d.ts","sourceRoot":"","sources":["../../src/client/stub.js"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"stub.d.ts","sourceRoot":"","sources":["../../src/client/stub.js"],"names":[],"mappings":"AAAA,6BAsEC"}
|
package/dist/client.iife.js
CHANGED
|
@@ -1586,15 +1586,15 @@ var HMR = (() => {
|
|
|
1586
1586
|
fetch(url).then((r) => {
|
|
1587
1587
|
if (!r.ok) throw new Error(`Failed to fetch CSS: ${path} (${r.status})`);
|
|
1588
1588
|
return r.text();
|
|
1589
|
-
}).then((code) =>
|
|
1590
|
-
this._inject("css", code, path);
|
|
1591
|
-
})
|
|
1589
|
+
}).then((code) => this._inject("css", code, path))
|
|
1592
1590
|
);
|
|
1593
1591
|
}
|
|
1594
1592
|
if (toParent) {
|
|
1595
1593
|
ops.push(this._loadCSSInParent(path, url));
|
|
1596
1594
|
}
|
|
1597
|
-
await Promise.
|
|
1595
|
+
const results = await Promise.allSettled(ops);
|
|
1596
|
+
const failed = results.find((r) => r.status === "rejected");
|
|
1597
|
+
if (failed) throw failed.reason;
|
|
1598
1598
|
return true;
|
|
1599
1599
|
}
|
|
1600
1600
|
_loadCSSInParent(path, url) {
|
|
@@ -1622,7 +1622,7 @@ var HMR = (() => {
|
|
|
1622
1622
|
if (!r.ok) throw new Error(`Failed to fetch module: ${path} (${r.status})`);
|
|
1623
1623
|
return r.text();
|
|
1624
1624
|
});
|
|
1625
|
-
this._inject("module", code, path);
|
|
1625
|
+
await this._inject("module", code, path);
|
|
1626
1626
|
return true;
|
|
1627
1627
|
}
|
|
1628
1628
|
await import(url);
|
|
@@ -1637,14 +1637,18 @@ var HMR = (() => {
|
|
|
1637
1637
|
if (!r.ok) throw new Error(`Failed to fetch script: ${path} (${r.status})`);
|
|
1638
1638
|
return r.text();
|
|
1639
1639
|
});
|
|
1640
|
-
this._inject("script", code, path);
|
|
1640
|
+
await this._inject("script", code, path);
|
|
1641
1641
|
return true;
|
|
1642
1642
|
}
|
|
1643
1643
|
const script = document.createElement("script");
|
|
1644
1644
|
script.src = url;
|
|
1645
1645
|
script.setAttribute("data-file", path);
|
|
1646
1646
|
return new Promise((resolve, reject) => {
|
|
1647
|
-
script.onload = () =>
|
|
1647
|
+
script.onload = () => {
|
|
1648
|
+
const previous = document.querySelector(`script[data-file="${path}"]:not([src="${url}"])`);
|
|
1649
|
+
if (previous) previous.remove();
|
|
1650
|
+
resolve(true);
|
|
1651
|
+
};
|
|
1648
1652
|
script.onerror = () => reject(new Error(`Failed to load script: ${path}`));
|
|
1649
1653
|
document.head.appendChild(script);
|
|
1650
1654
|
});
|
|
@@ -1686,8 +1690,7 @@ var HMR = (() => {
|
|
|
1686
1690
|
this.loadQueue.delete(path);
|
|
1687
1691
|
}
|
|
1688
1692
|
if (this.iframeTarget) {
|
|
1689
|
-
this.
|
|
1690
|
-
await Promise.resolve();
|
|
1693
|
+
await this._postAndAwaitAck({ type: "hmr:remove", file: path });
|
|
1691
1694
|
} else {
|
|
1692
1695
|
const el = document.querySelector(`[data-file="${path}"]`);
|
|
1693
1696
|
if (el) {
|
|
@@ -1703,13 +1706,27 @@ var HMR = (() => {
|
|
|
1703
1706
|
this.versions.set(path, v);
|
|
1704
1707
|
return `${this.httpUrl}${path}?v=${v}`;
|
|
1705
1708
|
}
|
|
1706
|
-
//
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
+
// Post a message and resolve once the stub sends back hmr:ack
|
|
1710
|
+
_postAndAwaitAck(message) {
|
|
1711
|
+
return new Promise((resolve) => {
|
|
1712
|
+
const onAck = (e) => {
|
|
1713
|
+
if (e.source !== this.iframeTarget) return;
|
|
1714
|
+
let data;
|
|
1715
|
+
try {
|
|
1716
|
+
data = JSON.parse(e.data);
|
|
1717
|
+
} catch {
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
if (data?.type !== "hmr:ack") return;
|
|
1721
|
+
window.removeEventListener("message", onAck);
|
|
1722
|
+
resolve();
|
|
1723
|
+
};
|
|
1724
|
+
window.addEventListener("message", onAck);
|
|
1725
|
+
this.iframeTarget.postMessage(JSON.stringify(message), this.iframeOrigin);
|
|
1726
|
+
});
|
|
1709
1727
|
}
|
|
1710
|
-
// Forward a file payload to the iframe target
|
|
1711
1728
|
_inject(kind, code, file) {
|
|
1712
|
-
this.
|
|
1729
|
+
return this._postAndAwaitAck({ type: "hmr:inject", kind, code, file });
|
|
1713
1730
|
}
|
|
1714
1731
|
};
|
|
1715
1732
|
|
|
@@ -2213,15 +2230,22 @@ var HMR = (() => {
|
|
|
2213
2230
|
this._processingMessages = false;
|
|
2214
2231
|
}
|
|
2215
2232
|
// Wait for stub's hmr:ready signal. Stub fires it proactively on run.
|
|
2216
|
-
// Times out after 5s
|
|
2233
|
+
// Times out after 5s and resolves anyway, a missing stub degrades gracefully.
|
|
2217
2234
|
_waitForStub() {
|
|
2218
|
-
return new Promise((resolve
|
|
2235
|
+
return new Promise((resolve) => {
|
|
2219
2236
|
const timer = setTimeout(() => {
|
|
2220
2237
|
window.removeEventListener("message", onReady);
|
|
2221
|
-
|
|
2238
|
+
this.log("warning", "Timed out waiting for hmr:ready. Was HMR.stub() called in the iframe?");
|
|
2239
|
+
resolve();
|
|
2222
2240
|
}, 5e3);
|
|
2223
2241
|
const onReady = (e) => {
|
|
2224
|
-
|
|
2242
|
+
let data;
|
|
2243
|
+
try {
|
|
2244
|
+
data = JSON.parse(e.data);
|
|
2245
|
+
} catch {
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
if (data?.type !== "hmr:ready") return;
|
|
2225
2249
|
const originOk = this._iframeOrigin === "*" || e.origin === this._iframeOrigin;
|
|
2226
2250
|
if (!originOk) return;
|
|
2227
2251
|
clearTimeout(timer);
|
|
@@ -2241,15 +2265,25 @@ var HMR = (() => {
|
|
|
2241
2265
|
_listenForReattach() {
|
|
2242
2266
|
if (this._onReattach) return;
|
|
2243
2267
|
this._onReattach = async (e) => {
|
|
2244
|
-
|
|
2268
|
+
let data;
|
|
2269
|
+
try {
|
|
2270
|
+
data = JSON.parse(e.data);
|
|
2271
|
+
} catch {
|
|
2272
|
+
return;
|
|
2273
|
+
}
|
|
2274
|
+
if (data?.type !== "hmr:ready") return;
|
|
2245
2275
|
const originOk = this._iframeOrigin === "*" || e.origin === this._iframeOrigin;
|
|
2246
2276
|
if (!originOk) return;
|
|
2247
2277
|
if (e.source === this._iframeTarget) return;
|
|
2248
2278
|
this._iframeTarget = e.source;
|
|
2249
2279
|
this.fileLoader.iframeTarget = e.source;
|
|
2250
2280
|
this.log("success", "HMR reattached to new iframe");
|
|
2251
|
-
for (const path of this.fileLoader.versions.keys()) {
|
|
2252
|
-
|
|
2281
|
+
for (const path of this.sortFiles([...this.fileLoader.versions.keys()])) {
|
|
2282
|
+
try {
|
|
2283
|
+
await this.fileLoader.loadFile(path);
|
|
2284
|
+
} catch (e2) {
|
|
2285
|
+
this.log("error", `Reattach failed to load ${path}: ${e2.message}`);
|
|
2286
|
+
}
|
|
2253
2287
|
}
|
|
2254
2288
|
};
|
|
2255
2289
|
window.addEventListener("message", this._onReattach);
|
|
@@ -2285,15 +2319,8 @@ var HMR = (() => {
|
|
|
2285
2319
|
this._messageQueue = [];
|
|
2286
2320
|
this._processingMessages = true;
|
|
2287
2321
|
if (this._iframeTarget || this._stubManaged) {
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
if (this._stubManaged) this._listenForReattach();
|
|
2291
|
-
} catch (e) {
|
|
2292
|
-
this.log("error", e.message);
|
|
2293
|
-
this._processingMessages = false;
|
|
2294
|
-
reject(e);
|
|
2295
|
-
return;
|
|
2296
|
-
}
|
|
2322
|
+
await this._waitForStub();
|
|
2323
|
+
if (this._stubManaged) this._listenForReattach();
|
|
2297
2324
|
}
|
|
2298
2325
|
this._processingMessages = false;
|
|
2299
2326
|
if (this._messageQueue.length > 0) this._drainMessageQueue();
|
|
@@ -2369,36 +2396,72 @@ var HMR = (() => {
|
|
|
2369
2396
|
const removeIfExists = (el) => {
|
|
2370
2397
|
if (el) el.remove();
|
|
2371
2398
|
};
|
|
2372
|
-
const injectScript = (kind, code, file) => {
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
|
|
2378
|
-
|
|
2379
|
-
|
|
2399
|
+
const injectScript = async (kind, code, file) => {
|
|
2400
|
+
const url = URL.createObjectURL(new Blob([code + `
|
|
2401
|
+
//# sourceURL=${file}`], { type: "text/javascript" }));
|
|
2402
|
+
try {
|
|
2403
|
+
if (kind === "module") {
|
|
2404
|
+
await import(url);
|
|
2405
|
+
} else {
|
|
2406
|
+
const script = document.createElement("script");
|
|
2407
|
+
script.src = url;
|
|
2408
|
+
await new Promise((resolve, reject) => {
|
|
2409
|
+
script.onload = resolve;
|
|
2410
|
+
script.onerror = () => reject(new Error(`Failed to execute script: ${file}`));
|
|
2411
|
+
document.documentElement.appendChild(script);
|
|
2412
|
+
});
|
|
2413
|
+
}
|
|
2414
|
+
} finally {
|
|
2415
|
+
URL.revokeObjectURL(url);
|
|
2416
|
+
}
|
|
2380
2417
|
};
|
|
2381
|
-
const injectStyle = (code, file) => {
|
|
2382
|
-
const existing = byFile("
|
|
2383
|
-
const
|
|
2384
|
-
|
|
2385
|
-
|
|
2386
|
-
|
|
2418
|
+
const injectStyle = async (code, file) => {
|
|
2419
|
+
const existing = byFile("link", file);
|
|
2420
|
+
const url = URL.createObjectURL(new Blob([code + `
|
|
2421
|
+
/*# sourceURL=${file} */`], { type: "text/css" }));
|
|
2422
|
+
const link = document.createElement("link");
|
|
2423
|
+
link.rel = "stylesheet";
|
|
2424
|
+
link.href = url;
|
|
2425
|
+
link.dataset.file = file;
|
|
2426
|
+
await new Promise((resolve, reject) => {
|
|
2427
|
+
link.onload = () => {
|
|
2428
|
+
URL.revokeObjectURL(url);
|
|
2429
|
+
resolve();
|
|
2430
|
+
};
|
|
2431
|
+
link.onerror = () => {
|
|
2432
|
+
URL.revokeObjectURL(url);
|
|
2433
|
+
reject(new Error(`Failed to load CSS: ${file}`));
|
|
2434
|
+
};
|
|
2435
|
+
document.head.appendChild(link);
|
|
2436
|
+
});
|
|
2387
2437
|
removeIfExists(existing);
|
|
2388
2438
|
};
|
|
2389
|
-
window.addEventListener("message", (e) => {
|
|
2390
|
-
|
|
2439
|
+
window.addEventListener("message", async (e) => {
|
|
2440
|
+
let data;
|
|
2441
|
+
try {
|
|
2442
|
+
data = JSON.parse(e.data);
|
|
2443
|
+
} catch {
|
|
2444
|
+
return;
|
|
2445
|
+
}
|
|
2391
2446
|
if (!data?.type) return;
|
|
2447
|
+
const ackOrigin = e.origin && e.origin !== "null" ? e.origin : "*";
|
|
2448
|
+
const ack = () => e.source?.postMessage(JSON.stringify({ type: "hmr:ack" }), ackOrigin);
|
|
2392
2449
|
if (data.type === "hmr:remove") {
|
|
2393
2450
|
removeIfExists(document.querySelector(`[data-file="${CSS.escape(data.file)}"]`));
|
|
2451
|
+
ack();
|
|
2394
2452
|
return;
|
|
2395
2453
|
}
|
|
2396
2454
|
if (data.type !== "hmr:inject") return;
|
|
2397
2455
|
const { kind, code, file } = data;
|
|
2398
|
-
|
|
2399
|
-
|
|
2456
|
+
try {
|
|
2457
|
+
if (kind === "script" || kind === "module") await injectScript(kind, code, file);
|
|
2458
|
+
else if (kind === "css") await injectStyle(code, file);
|
|
2459
|
+
} catch (err) {
|
|
2460
|
+
console.error(`Failed to inject ${file}:`, err.message ?? err, "\n" + err.stack);
|
|
2461
|
+
}
|
|
2462
|
+
ack();
|
|
2400
2463
|
});
|
|
2401
|
-
window.parent.postMessage({ type: "hmr:ready" }, "*");
|
|
2464
|
+
window.parent.postMessage(JSON.stringify({ type: "hmr:ready" }), "*");
|
|
2402
2465
|
}
|
|
2403
2466
|
return __toCommonJS(client_exports);
|
|
2404
2467
|
})();
|