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/dist/client.js
CHANGED
|
@@ -1572,15 +1572,15 @@ var FileLoader = class {
|
|
|
1572
1572
|
fetch(url).then((r) => {
|
|
1573
1573
|
if (!r.ok) throw new Error(`Failed to fetch CSS: ${path} (${r.status})`);
|
|
1574
1574
|
return r.text();
|
|
1575
|
-
}).then((code) =>
|
|
1576
|
-
this._inject("css", code, path);
|
|
1577
|
-
})
|
|
1575
|
+
}).then((code) => this._inject("css", code, path))
|
|
1578
1576
|
);
|
|
1579
1577
|
}
|
|
1580
1578
|
if (toParent) {
|
|
1581
1579
|
ops.push(this._loadCSSInParent(path, url));
|
|
1582
1580
|
}
|
|
1583
|
-
await Promise.
|
|
1581
|
+
const results = await Promise.allSettled(ops);
|
|
1582
|
+
const failed = results.find((r) => r.status === "rejected");
|
|
1583
|
+
if (failed) throw failed.reason;
|
|
1584
1584
|
return true;
|
|
1585
1585
|
}
|
|
1586
1586
|
_loadCSSInParent(path, url) {
|
|
@@ -1608,7 +1608,7 @@ var FileLoader = class {
|
|
|
1608
1608
|
if (!r.ok) throw new Error(`Failed to fetch module: ${path} (${r.status})`);
|
|
1609
1609
|
return r.text();
|
|
1610
1610
|
});
|
|
1611
|
-
this._inject("module", code, path);
|
|
1611
|
+
await this._inject("module", code, path);
|
|
1612
1612
|
return true;
|
|
1613
1613
|
}
|
|
1614
1614
|
await import(url);
|
|
@@ -1623,14 +1623,18 @@ var FileLoader = class {
|
|
|
1623
1623
|
if (!r.ok) throw new Error(`Failed to fetch script: ${path} (${r.status})`);
|
|
1624
1624
|
return r.text();
|
|
1625
1625
|
});
|
|
1626
|
-
this._inject("script", code, path);
|
|
1626
|
+
await this._inject("script", code, path);
|
|
1627
1627
|
return true;
|
|
1628
1628
|
}
|
|
1629
1629
|
const script = document.createElement("script");
|
|
1630
1630
|
script.src = url;
|
|
1631
1631
|
script.setAttribute("data-file", path);
|
|
1632
1632
|
return new Promise((resolve, reject) => {
|
|
1633
|
-
script.onload = () =>
|
|
1633
|
+
script.onload = () => {
|
|
1634
|
+
const previous = document.querySelector(`script[data-file="${path}"]:not([src="${url}"])`);
|
|
1635
|
+
if (previous) previous.remove();
|
|
1636
|
+
resolve(true);
|
|
1637
|
+
};
|
|
1634
1638
|
script.onerror = () => reject(new Error(`Failed to load script: ${path}`));
|
|
1635
1639
|
document.head.appendChild(script);
|
|
1636
1640
|
});
|
|
@@ -1672,8 +1676,7 @@ var FileLoader = class {
|
|
|
1672
1676
|
this.loadQueue.delete(path);
|
|
1673
1677
|
}
|
|
1674
1678
|
if (this.iframeTarget) {
|
|
1675
|
-
this.
|
|
1676
|
-
await Promise.resolve();
|
|
1679
|
+
await this._postAndAwaitAck({ type: "hmr:remove", file: path });
|
|
1677
1680
|
} else {
|
|
1678
1681
|
const el = document.querySelector(`[data-file="${path}"]`);
|
|
1679
1682
|
if (el) {
|
|
@@ -1689,13 +1692,27 @@ var FileLoader = class {
|
|
|
1689
1692
|
this.versions.set(path, v);
|
|
1690
1693
|
return `${this.httpUrl}${path}?v=${v}`;
|
|
1691
1694
|
}
|
|
1692
|
-
//
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
+
// Post a message and resolve once the stub sends back hmr:ack
|
|
1696
|
+
_postAndAwaitAck(message) {
|
|
1697
|
+
return new Promise((resolve) => {
|
|
1698
|
+
const onAck = (e) => {
|
|
1699
|
+
if (e.source !== this.iframeTarget) return;
|
|
1700
|
+
let data;
|
|
1701
|
+
try {
|
|
1702
|
+
data = JSON.parse(e.data);
|
|
1703
|
+
} catch {
|
|
1704
|
+
return;
|
|
1705
|
+
}
|
|
1706
|
+
if (data?.type !== "hmr:ack") return;
|
|
1707
|
+
window.removeEventListener("message", onAck);
|
|
1708
|
+
resolve();
|
|
1709
|
+
};
|
|
1710
|
+
window.addEventListener("message", onAck);
|
|
1711
|
+
this.iframeTarget.postMessage(JSON.stringify(message), this.iframeOrigin);
|
|
1712
|
+
});
|
|
1695
1713
|
}
|
|
1696
|
-
// Forward a file payload to the iframe target
|
|
1697
1714
|
_inject(kind, code, file) {
|
|
1698
|
-
this.
|
|
1715
|
+
return this._postAndAwaitAck({ type: "hmr:inject", kind, code, file });
|
|
1699
1716
|
}
|
|
1700
1717
|
};
|
|
1701
1718
|
|
|
@@ -2199,15 +2216,22 @@ var HMRClient = class {
|
|
|
2199
2216
|
this._processingMessages = false;
|
|
2200
2217
|
}
|
|
2201
2218
|
// Wait for stub's hmr:ready signal. Stub fires it proactively on run.
|
|
2202
|
-
// Times out after 5s
|
|
2219
|
+
// Times out after 5s and resolves anyway, a missing stub degrades gracefully.
|
|
2203
2220
|
_waitForStub() {
|
|
2204
|
-
return new Promise((resolve
|
|
2221
|
+
return new Promise((resolve) => {
|
|
2205
2222
|
const timer = setTimeout(() => {
|
|
2206
2223
|
window.removeEventListener("message", onReady);
|
|
2207
|
-
|
|
2224
|
+
this.log("warning", "Timed out waiting for hmr:ready. Was HMR.stub() called in the iframe?");
|
|
2225
|
+
resolve();
|
|
2208
2226
|
}, 5e3);
|
|
2209
2227
|
const onReady = (e) => {
|
|
2210
|
-
|
|
2228
|
+
let data;
|
|
2229
|
+
try {
|
|
2230
|
+
data = JSON.parse(e.data);
|
|
2231
|
+
} catch {
|
|
2232
|
+
return;
|
|
2233
|
+
}
|
|
2234
|
+
if (data?.type !== "hmr:ready") return;
|
|
2211
2235
|
const originOk = this._iframeOrigin === "*" || e.origin === this._iframeOrigin;
|
|
2212
2236
|
if (!originOk) return;
|
|
2213
2237
|
clearTimeout(timer);
|
|
@@ -2227,15 +2251,25 @@ var HMRClient = class {
|
|
|
2227
2251
|
_listenForReattach() {
|
|
2228
2252
|
if (this._onReattach) return;
|
|
2229
2253
|
this._onReattach = async (e) => {
|
|
2230
|
-
|
|
2254
|
+
let data;
|
|
2255
|
+
try {
|
|
2256
|
+
data = JSON.parse(e.data);
|
|
2257
|
+
} catch {
|
|
2258
|
+
return;
|
|
2259
|
+
}
|
|
2260
|
+
if (data?.type !== "hmr:ready") return;
|
|
2231
2261
|
const originOk = this._iframeOrigin === "*" || e.origin === this._iframeOrigin;
|
|
2232
2262
|
if (!originOk) return;
|
|
2233
2263
|
if (e.source === this._iframeTarget) return;
|
|
2234
2264
|
this._iframeTarget = e.source;
|
|
2235
2265
|
this.fileLoader.iframeTarget = e.source;
|
|
2236
2266
|
this.log("success", "HMR reattached to new iframe");
|
|
2237
|
-
for (const path of this.fileLoader.versions.keys()) {
|
|
2238
|
-
|
|
2267
|
+
for (const path of this.sortFiles([...this.fileLoader.versions.keys()])) {
|
|
2268
|
+
try {
|
|
2269
|
+
await this.fileLoader.loadFile(path);
|
|
2270
|
+
} catch (e2) {
|
|
2271
|
+
this.log("error", `Reattach failed to load ${path}: ${e2.message}`);
|
|
2272
|
+
}
|
|
2239
2273
|
}
|
|
2240
2274
|
};
|
|
2241
2275
|
window.addEventListener("message", this._onReattach);
|
|
@@ -2271,15 +2305,8 @@ var HMRClient = class {
|
|
|
2271
2305
|
this._messageQueue = [];
|
|
2272
2306
|
this._processingMessages = true;
|
|
2273
2307
|
if (this._iframeTarget || this._stubManaged) {
|
|
2274
|
-
|
|
2275
|
-
|
|
2276
|
-
if (this._stubManaged) this._listenForReattach();
|
|
2277
|
-
} catch (e) {
|
|
2278
|
-
this.log("error", e.message);
|
|
2279
|
-
this._processingMessages = false;
|
|
2280
|
-
reject(e);
|
|
2281
|
-
return;
|
|
2282
|
-
}
|
|
2308
|
+
await this._waitForStub();
|
|
2309
|
+
if (this._stubManaged) this._listenForReattach();
|
|
2283
2310
|
}
|
|
2284
2311
|
this._processingMessages = false;
|
|
2285
2312
|
if (this._messageQueue.length > 0) this._drainMessageQueue();
|
|
@@ -2355,36 +2382,72 @@ function stub() {
|
|
|
2355
2382
|
const removeIfExists = (el) => {
|
|
2356
2383
|
if (el) el.remove();
|
|
2357
2384
|
};
|
|
2358
|
-
const injectScript = (kind, code, file) => {
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2385
|
+
const injectScript = async (kind, code, file) => {
|
|
2386
|
+
const url = URL.createObjectURL(new Blob([code + `
|
|
2387
|
+
//# sourceURL=${file}`], { type: "text/javascript" }));
|
|
2388
|
+
try {
|
|
2389
|
+
if (kind === "module") {
|
|
2390
|
+
await import(url);
|
|
2391
|
+
} else {
|
|
2392
|
+
const script = document.createElement("script");
|
|
2393
|
+
script.src = url;
|
|
2394
|
+
await new Promise((resolve, reject) => {
|
|
2395
|
+
script.onload = resolve;
|
|
2396
|
+
script.onerror = () => reject(new Error(`Failed to execute script: ${file}`));
|
|
2397
|
+
document.documentElement.appendChild(script);
|
|
2398
|
+
});
|
|
2399
|
+
}
|
|
2400
|
+
} finally {
|
|
2401
|
+
URL.revokeObjectURL(url);
|
|
2402
|
+
}
|
|
2366
2403
|
};
|
|
2367
|
-
const injectStyle = (code, file) => {
|
|
2368
|
-
const existing = byFile("
|
|
2369
|
-
const
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2404
|
+
const injectStyle = async (code, file) => {
|
|
2405
|
+
const existing = byFile("link", file);
|
|
2406
|
+
const url = URL.createObjectURL(new Blob([code + `
|
|
2407
|
+
/*# sourceURL=${file} */`], { type: "text/css" }));
|
|
2408
|
+
const link = document.createElement("link");
|
|
2409
|
+
link.rel = "stylesheet";
|
|
2410
|
+
link.href = url;
|
|
2411
|
+
link.dataset.file = file;
|
|
2412
|
+
await new Promise((resolve, reject) => {
|
|
2413
|
+
link.onload = () => {
|
|
2414
|
+
URL.revokeObjectURL(url);
|
|
2415
|
+
resolve();
|
|
2416
|
+
};
|
|
2417
|
+
link.onerror = () => {
|
|
2418
|
+
URL.revokeObjectURL(url);
|
|
2419
|
+
reject(new Error(`Failed to load CSS: ${file}`));
|
|
2420
|
+
};
|
|
2421
|
+
document.head.appendChild(link);
|
|
2422
|
+
});
|
|
2373
2423
|
removeIfExists(existing);
|
|
2374
2424
|
};
|
|
2375
|
-
window.addEventListener("message", (e) => {
|
|
2376
|
-
|
|
2425
|
+
window.addEventListener("message", async (e) => {
|
|
2426
|
+
let data;
|
|
2427
|
+
try {
|
|
2428
|
+
data = JSON.parse(e.data);
|
|
2429
|
+
} catch {
|
|
2430
|
+
return;
|
|
2431
|
+
}
|
|
2377
2432
|
if (!data?.type) return;
|
|
2433
|
+
const ackOrigin = e.origin && e.origin !== "null" ? e.origin : "*";
|
|
2434
|
+
const ack = () => e.source?.postMessage(JSON.stringify({ type: "hmr:ack" }), ackOrigin);
|
|
2378
2435
|
if (data.type === "hmr:remove") {
|
|
2379
2436
|
removeIfExists(document.querySelector(`[data-file="${CSS.escape(data.file)}"]`));
|
|
2437
|
+
ack();
|
|
2380
2438
|
return;
|
|
2381
2439
|
}
|
|
2382
2440
|
if (data.type !== "hmr:inject") return;
|
|
2383
2441
|
const { kind, code, file } = data;
|
|
2384
|
-
|
|
2385
|
-
|
|
2442
|
+
try {
|
|
2443
|
+
if (kind === "script" || kind === "module") await injectScript(kind, code, file);
|
|
2444
|
+
else if (kind === "css") await injectStyle(code, file);
|
|
2445
|
+
} catch (err) {
|
|
2446
|
+
console.error(`Failed to inject ${file}:`, err.message ?? err, "\n" + err.stack);
|
|
2447
|
+
}
|
|
2448
|
+
ack();
|
|
2386
2449
|
});
|
|
2387
|
-
window.parent.postMessage({ type: "hmr:ready" }, "*");
|
|
2450
|
+
window.parent.postMessage(JSON.stringify({ type: "hmr:ready" }), "*");
|
|
2388
2451
|
}
|
|
2389
2452
|
export {
|
|
2390
2453
|
HMRClient,
|