@absolutejs/absolute 0.20.0-beta.139 → 0.20.0-beta.140
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/CHANGELOG.md +11 -0
- package/changelog.json +21 -0
- package/dist/angular/components/core/streamingSlotRegistrar.js +1 -1
- package/dist/angular/components/core/streamingSlotRegistry.js +2 -2
- package/dist/build.js +25 -6
- package/dist/build.js.map +6 -6
- package/dist/dev/client/hmrClient.ts +88 -36
- package/dist/dev/client/reconnect.ts +43 -0
- package/dist/index.js +25 -6
- package/dist/index.js.map +6 -6
- package/dist/src/build/buildReactVendor.d.ts +3 -1
- package/package.json +1 -1
|
@@ -5,12 +5,15 @@ import type {} from '../../types/globals';
|
|
|
5
5
|
import { hmrState } from './hmrState';
|
|
6
6
|
import {
|
|
7
7
|
HMR_UPDATE_TIMEOUT_MS,
|
|
8
|
-
MAX_RECONNECT_ATTEMPTS,
|
|
9
8
|
PING_INTERVAL_MS,
|
|
10
|
-
RECONNECT_INITIAL_DELAY_MS,
|
|
11
|
-
RECONNECT_POLL_INTERVAL_MS,
|
|
12
9
|
WEBSOCKET_NORMAL_CLOSURE
|
|
13
10
|
} from './constants';
|
|
11
|
+
import {
|
|
12
|
+
RECONNECT_GIVE_UP_MS,
|
|
13
|
+
missedWhileDisconnected,
|
|
14
|
+
reconnectDelayMs,
|
|
15
|
+
type ServerSnapshot
|
|
16
|
+
} from './reconnect';
|
|
14
17
|
import { detectCurrentFramework } from './frameworkDetect';
|
|
15
18
|
import {
|
|
16
19
|
absoluteHmrClientTarget,
|
|
@@ -103,11 +106,9 @@ const removeNativeSyncDevtools =
|
|
|
103
106
|
? () => undefined
|
|
104
107
|
: installAbsoluteNativeSyncDevtools();
|
|
105
108
|
|
|
106
|
-
/* Lightweight "server disconnected" banner
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
* a branded, self-explanatory notice on screen while the client polls
|
|
110
|
-
* `/hmr-status` and reloads on recovery. Kept separate from the compile
|
|
109
|
+
/* Lightweight "server disconnected" banner, shown while the socket is
|
|
110
|
+
* down (a dropped network or a restarting server) and the client reconnects.
|
|
111
|
+
* The page reloads on recovery only if it missed an update. Kept separate from the compile
|
|
111
112
|
* error overlay so it never clobbers a build-error message. The
|
|
112
113
|
* `data-hmr-overlay` attribute exempts it from HMR DOM diffing. */
|
|
113
114
|
const CONNECTION_LOST_BANNER_ID = 'absolutejs-connection-lost';
|
|
@@ -130,7 +131,10 @@ const showConnectionLostBanner = () => {
|
|
|
130
131
|
'text-align:center',
|
|
131
132
|
'box-shadow:0 -2px 12px rgba(0,0,0,0.3)'
|
|
132
133
|
].join(';');
|
|
133
|
-
banner.textContent =
|
|
134
|
+
banner.textContent =
|
|
135
|
+
navigator.onLine === false
|
|
136
|
+
? 'AbsoluteJS · offline — reconnects when the network is back'
|
|
137
|
+
: 'AbsoluteJS · dev server disconnected — reconnecting…';
|
|
134
138
|
document.body.appendChild(banner);
|
|
135
139
|
};
|
|
136
140
|
const hideConnectionLostBanner = () => {
|
|
@@ -203,6 +207,7 @@ type HMRMessage = {
|
|
|
203
207
|
// BUN-REACT-REFRESH-LEGACY: false only on stock Bun (see handlers/react.ts).
|
|
204
208
|
fastRefreshSupported?: boolean;
|
|
205
209
|
file?: string;
|
|
210
|
+
lastBroadcastAt?: number;
|
|
206
211
|
framework?: string;
|
|
207
212
|
hasCSSChanges?: boolean;
|
|
208
213
|
hasComponentChanges?: boolean;
|
|
@@ -217,6 +222,7 @@ type HMRMessage = {
|
|
|
217
222
|
primarySource?: string;
|
|
218
223
|
scriptUrl?: string;
|
|
219
224
|
serverDuration?: number;
|
|
225
|
+
serverStartedAt?: number;
|
|
220
226
|
serverVersions?: Record<string, number>;
|
|
221
227
|
};
|
|
222
228
|
timestamp?: number;
|
|
@@ -381,8 +387,43 @@ const handleHMRMessage = (message: HMRMessage) => {
|
|
|
381
387
|
}
|
|
382
388
|
};
|
|
383
389
|
|
|
384
|
-
//
|
|
385
|
-
|
|
390
|
+
// What the server said when this page last connected, and the newest update
|
|
391
|
+
// the page received: on reconnecting, the page reloads only if it missed one.
|
|
392
|
+
let serverSnapshot: ServerSnapshot | undefined;
|
|
393
|
+
let lastReceivedAt = 0;
|
|
394
|
+
let reconnectAttempt = 0;
|
|
395
|
+
let disconnectedAt = 0;
|
|
396
|
+
|
|
397
|
+
const scheduleReconnect = (connect: () => void) => {
|
|
398
|
+
if (hmrState.reconnectTimeout) clearTimeout(hmrState.reconnectTimeout);
|
|
399
|
+
if (!disconnectedAt) disconnectedAt = Date.now();
|
|
400
|
+
if (Date.now() - disconnectedAt > RECONNECT_GIVE_UP_MS) return;
|
|
401
|
+
// An offline browser waits for the network instead of spending attempts.
|
|
402
|
+
if (navigator.onLine === false) return;
|
|
403
|
+
hmrState.reconnectTimeout = setTimeout(
|
|
404
|
+
connect,
|
|
405
|
+
reconnectDelayMs(reconnectAttempt)
|
|
406
|
+
);
|
|
407
|
+
reconnectAttempt += 1;
|
|
408
|
+
};
|
|
409
|
+
|
|
410
|
+
const receivedSnapshot = (message: HMRMessage) => {
|
|
411
|
+
const after: ServerSnapshot = {
|
|
412
|
+
lastBroadcastAt: message.data.lastBroadcastAt,
|
|
413
|
+
serverStartedAt: message.data.serverStartedAt
|
|
414
|
+
};
|
|
415
|
+
const missed = missedWhileDisconnected(
|
|
416
|
+
serverSnapshot,
|
|
417
|
+
after,
|
|
418
|
+
lastReceivedAt
|
|
419
|
+
);
|
|
420
|
+
if (!serverSnapshot) lastReceivedAt = after.lastBroadcastAt ?? 0;
|
|
421
|
+
serverSnapshot = after;
|
|
422
|
+
|
|
423
|
+
return missed;
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
const connectHmrSocket = () => {
|
|
386
427
|
// Determine WebSocket URL
|
|
387
428
|
const wsHost = location.hostname;
|
|
388
429
|
const wsPort =
|
|
@@ -395,6 +436,8 @@ if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
|
395
436
|
|
|
396
437
|
wsc.onopen = function () {
|
|
397
438
|
hmrState.isConnected = true;
|
|
439
|
+
reconnectAttempt = 0;
|
|
440
|
+
disconnectedAt = 0;
|
|
398
441
|
hideConnectionLostBanner();
|
|
399
442
|
sessionStorage.setItem('__HMR_CONNECTED__', 'true');
|
|
400
443
|
|
|
@@ -427,6 +470,20 @@ if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
|
427
470
|
return;
|
|
428
471
|
}
|
|
429
472
|
|
|
473
|
+
if (message?.type === 'manifest' && receivedSnapshot(message)) {
|
|
474
|
+
// The server restarted or sent updates while this page was
|
|
475
|
+
// away; only a reload is sure to show the current build.
|
|
476
|
+
window.location.reload();
|
|
477
|
+
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (
|
|
481
|
+
typeof message?.timestamp === 'number' &&
|
|
482
|
+
message.type !== 'manifest' &&
|
|
483
|
+
message.type !== 'connected' &&
|
|
484
|
+
message.type !== 'pong'
|
|
485
|
+
)
|
|
486
|
+
lastReceivedAt = Math.max(lastReceivedAt, message.timestamp);
|
|
430
487
|
handleHMRMessage(message);
|
|
431
488
|
};
|
|
432
489
|
|
|
@@ -440,37 +497,32 @@ if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
|
440
497
|
|
|
441
498
|
if (event.code !== WEBSOCKET_NORMAL_CLOSURE) {
|
|
442
499
|
showConnectionLostBanner();
|
|
443
|
-
|
|
444
|
-
hmrState.reconnectTimeout = setTimeout(function pollServer() {
|
|
445
|
-
attempts++;
|
|
446
|
-
if (attempts > MAX_RECONNECT_ATTEMPTS) return;
|
|
447
|
-
|
|
448
|
-
fetch('/hmr-status', { cache: 'no-store' })
|
|
449
|
-
.then((res) => {
|
|
450
|
-
if (res.ok) {
|
|
451
|
-
window.location.reload();
|
|
452
|
-
} else {
|
|
453
|
-
hmrState.reconnectTimeout = setTimeout(
|
|
454
|
-
pollServer,
|
|
455
|
-
RECONNECT_POLL_INTERVAL_MS
|
|
456
|
-
);
|
|
457
|
-
}
|
|
458
|
-
|
|
459
|
-
return undefined;
|
|
460
|
-
})
|
|
461
|
-
.catch(() => {
|
|
462
|
-
hmrState.reconnectTimeout = setTimeout(
|
|
463
|
-
pollServer,
|
|
464
|
-
RECONNECT_POLL_INTERVAL_MS
|
|
465
|
-
);
|
|
466
|
-
});
|
|
467
|
-
}, RECONNECT_INITIAL_DELAY_MS);
|
|
500
|
+
scheduleReconnect(connectHmrSocket);
|
|
468
501
|
}
|
|
469
502
|
};
|
|
470
503
|
|
|
471
504
|
wsc.onerror = function () {
|
|
472
505
|
hmrState.isConnected = false;
|
|
473
506
|
};
|
|
507
|
+
};
|
|
508
|
+
|
|
509
|
+
// The network or the tab coming back is the moment to retry, not the next
|
|
510
|
+
// backoff step.
|
|
511
|
+
const reconnectNow = () => {
|
|
512
|
+
if (hmrState.isConnected || !disconnectedAt) return;
|
|
513
|
+
reconnectAttempt = 0;
|
|
514
|
+
if (hmrState.reconnectTimeout) clearTimeout(hmrState.reconnectTimeout);
|
|
515
|
+
hmrState.reconnectTimeout = null;
|
|
516
|
+
connectHmrSocket();
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
// Prevent multiple WebSocket connections
|
|
520
|
+
if (!(window.__HMR_WS__ && window.__HMR_WS__.readyState === WebSocket.OPEN)) {
|
|
521
|
+
connectHmrSocket();
|
|
522
|
+
window.addEventListener('online', reconnectNow);
|
|
523
|
+
document.addEventListener('visibilitychange', () => {
|
|
524
|
+
if (document.visibilityState === 'visible') reconnectNow();
|
|
525
|
+
});
|
|
474
526
|
|
|
475
527
|
window.addEventListener('beforeunload', () => {
|
|
476
528
|
removeNativeSyncDevtools();
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type {} from '../../types/globals';
|
|
2
|
+
/* When the dev-server socket drops, the page used to poll for about 18
|
|
3
|
+
seconds and reload as soon as the server answered. On weak wifi every
|
|
4
|
+
network change became a full reload that refetched every stylesheet and
|
|
5
|
+
script and lost the page's state, and an outage longer than 18 seconds
|
|
6
|
+
left the page disconnected for good. Now the socket reconnects for as long
|
|
7
|
+
as the page is open, and the page reloads only when it missed something:
|
|
8
|
+
the server restarted, or the build changed while it was away. */
|
|
9
|
+
|
|
10
|
+
export const RECONNECT_BASE_DELAY_MS = 500;
|
|
11
|
+
export const RECONNECT_GIVE_UP_MS = 30 * 60_000;
|
|
12
|
+
export const RECONNECT_MAX_DELAY_MS = 10_000;
|
|
13
|
+
|
|
14
|
+
export const reconnectDelayMs = (attempt: number) =>
|
|
15
|
+
Math.min(RECONNECT_BASE_DELAY_MS * 2 ** attempt, RECONNECT_MAX_DELAY_MS);
|
|
16
|
+
|
|
17
|
+
/* What the server says about itself when a socket connects. */
|
|
18
|
+
export type ServerSnapshot = {
|
|
19
|
+
/** When the last update went out to connected pages. */
|
|
20
|
+
lastBroadcastAt?: number;
|
|
21
|
+
/** When this server process started; a new value means it restarted. */
|
|
22
|
+
serverStartedAt?: number;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/* Whether the page has to reload after reconnecting: the server restarted,
|
|
26
|
+
or it sent an update after the last one this page received. Without a
|
|
27
|
+
previous snapshot (the first connection) there is nothing to have missed;
|
|
28
|
+
a server that does not say when it started counts as restarted, which is
|
|
29
|
+
the old behavior. */
|
|
30
|
+
export const missedWhileDisconnected = (
|
|
31
|
+
before: ServerSnapshot | undefined,
|
|
32
|
+
after: ServerSnapshot,
|
|
33
|
+
lastReceivedAt: number
|
|
34
|
+
) => {
|
|
35
|
+
if (!before) return false;
|
|
36
|
+
if (
|
|
37
|
+
before.serverStartedAt === undefined ||
|
|
38
|
+
before.serverStartedAt !== after.serverStartedAt
|
|
39
|
+
)
|
|
40
|
+
return true;
|
|
41
|
+
|
|
42
|
+
return (after.lastBroadcastAt ?? 0) > lastReceivedAt;
|
|
43
|
+
};
|
package/dist/index.js
CHANGED
|
@@ -25399,7 +25399,7 @@ var resolveJsxDevRuntimeCompatPath = () => {
|
|
|
25399
25399
|
return `${lines.join(`
|
|
25400
25400
|
`)}
|
|
25401
25401
|
`;
|
|
25402
|
-
}, buildReactVendor = async (buildDir) => {
|
|
25402
|
+
}, buildReactVendor = async (buildDir, { production = false } = {}) => {
|
|
25403
25403
|
const vendorDir = join47(buildDir, "react", "vendor");
|
|
25404
25404
|
mkdirSync8(vendorDir, { recursive: true });
|
|
25405
25405
|
const tmpDir = join47(buildDir, "_vendor_tmp");
|
|
@@ -25413,9 +25413,10 @@ var resolveJsxDevRuntimeCompatPath = () => {
|
|
|
25413
25413
|
return entryPath;
|
|
25414
25414
|
}));
|
|
25415
25415
|
const result = await bunBuild3({
|
|
25416
|
+
...production ? { define: { "process.env.NODE_ENV": '"production"' } } : {},
|
|
25416
25417
|
entrypoints,
|
|
25417
25418
|
format: "esm",
|
|
25418
|
-
minify: false,
|
|
25419
|
+
minify: production ? { whitespace: true } : false,
|
|
25419
25420
|
naming: "[name].[ext]",
|
|
25420
25421
|
outdir: vendorDir,
|
|
25421
25422
|
splitting: true,
|
|
@@ -26931,7 +26932,7 @@ ${offenders.map((o) => ` \u2022 ${o}`).join(`
|
|
|
26931
26932
|
}
|
|
26932
26933
|
if (!hmr && reactDir) {
|
|
26933
26934
|
await Promise.resolve().then(() => init_buildReactVendor());
|
|
26934
|
-
await buildReactVendor(buildPath);
|
|
26935
|
+
await buildReactVendor(buildPath, { production: !isDev });
|
|
26935
26936
|
vendorPaths = computeVendorPaths();
|
|
26936
26937
|
setDevVendorPaths(vendorPaths);
|
|
26937
26938
|
}
|
|
@@ -29509,12 +29510,14 @@ var MAX_RETAINED_HMR_UPDATES = 100, normalizedHmrTarget = (value) => {
|
|
|
29509
29510
|
state.connectedClients.delete(client);
|
|
29510
29511
|
state.clientTargets.delete(client);
|
|
29511
29512
|
});
|
|
29512
|
-
}, handleClientConnect = (state, client, manifest) => {
|
|
29513
|
+
}, SERVER_STARTED_AT, handleClientConnect = (state, client, manifest) => {
|
|
29513
29514
|
state.connectedClients.add(canonicalClient(client));
|
|
29514
29515
|
const serverVersions = serializeModuleVersions(state.moduleVersions);
|
|
29515
29516
|
client.send(JSON.stringify({
|
|
29516
29517
|
data: {
|
|
29518
|
+
lastBroadcastAt: state.lastBroadcastTimestamp,
|
|
29517
29519
|
manifest,
|
|
29520
|
+
serverStartedAt: SERVER_STARTED_AT,
|
|
29518
29521
|
serverVersions
|
|
29519
29522
|
},
|
|
29520
29523
|
timestamp: Date.now(),
|
|
@@ -29634,6 +29637,7 @@ var init_webSocket = __esm(() => {
|
|
|
29634
29637
|
init_telemetryEvent();
|
|
29635
29638
|
init_logger();
|
|
29636
29639
|
canonicalClients = new WeakMap;
|
|
29640
|
+
SERVER_STARTED_AT = Math.round(performance.timeOrigin);
|
|
29637
29641
|
});
|
|
29638
29642
|
|
|
29639
29643
|
// src/dev/moduleServer.ts
|
|
@@ -33118,6 +33122,20 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
|
|
|
33118
33122
|
return nearest;
|
|
33119
33123
|
const dependents = reactFiles.filter((candidate) => !edited.has(candidate) && isReactComponentPath(candidate) && isImportableModule(candidate));
|
|
33120
33124
|
return dependents.find((candidate) => !isReactPagePath(candidate)) ?? dependents[0] ?? file;
|
|
33125
|
+
}, MAX_REFRESH_BOUNDARY_HOPS = 8, registersRefreshComponent = (file) => /\$RefreshReg\$\(/u.test(getTransformed(resolvePath(file)) ?? ""), refreshBoundaryUrls = async (targets) => {
|
|
33126
|
+
const urls = [];
|
|
33127
|
+
const seen = new Set(targets.map((file) => resolvePath(file)));
|
|
33128
|
+
const climb = async (file, hops) => {
|
|
33129
|
+
const importer = findNearestComponent(resolvePath(file));
|
|
33130
|
+
if (!importer || seen.has(importer) || hops >= MAX_REFRESH_BOUNDARY_HOPS)
|
|
33131
|
+
return;
|
|
33132
|
+
seen.add(importer);
|
|
33133
|
+
urls.push(await getReactModuleUrl(importer));
|
|
33134
|
+
if (!registersRefreshComponent(importer))
|
|
33135
|
+
await climb(importer, hops + 1);
|
|
33136
|
+
};
|
|
33137
|
+
await targets.reduce((previous, target) => previous.then(() => registersRefreshComponent(target) ? undefined : climb(target, 0)), Promise.resolve());
|
|
33138
|
+
return urls;
|
|
33121
33139
|
}, resolveReactUpdateTargets = (state, reactFiles) => {
|
|
33122
33140
|
const importable = reactFiles.filter(isImportableModule);
|
|
33123
33141
|
const userEdited = importable.filter((file) => state.lastUserEditedFiles?.has(resolvePath(file)));
|
|
@@ -33150,7 +33168,8 @@ var moduleServerPromise, getModuleServer = () => moduleServerPromise, clearDevSs
|
|
|
33150
33168
|
});
|
|
33151
33169
|
return state.manifest;
|
|
33152
33170
|
}
|
|
33153
|
-
const
|
|
33171
|
+
const targetUrls = await Promise.all(targets.map(getReactModuleUrl));
|
|
33172
|
+
const moduleUrls = fastRefreshSupported ? [...targetUrls, ...await refreshBoundaryUrls(targets)] : targetUrls;
|
|
33154
33173
|
await Promise.all(editedFiles.filter((file) => !targets.includes(file)).map(getReactModuleUrl));
|
|
33155
33174
|
const { getTransformError } = await getModuleServer();
|
|
33156
33175
|
const failed = [...new Set([...editedFiles, ...targets])].map((file) => ({ error: getTransformError(file), file })).find((entry) => entry.error !== undefined);
|
|
@@ -43832,5 +43851,5 @@ export {
|
|
|
43832
43851
|
wrapPageHandlerWithStreamingSlots
|
|
43833
43852
|
};
|
|
43834
43853
|
|
|
43835
|
-
//# debugId=
|
|
43854
|
+
//# debugId=D311F2FBC012903E64756E2164756E21
|
|
43836
43855
|
//# sourceMappingURL=index.js.map
|