@steve31415/baselib 3.21.0 → 3.22.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.
|
@@ -26,8 +26,17 @@ export interface BuildUpdateDeps {
|
|
|
26
26
|
reload?: () => void;
|
|
27
27
|
pollMs?: number;
|
|
28
28
|
onTrafficBuildChange?: (buildId: string) => void;
|
|
29
|
+
/** Whether this document's HTML came from the browser cache without a
|
|
30
|
+
* request (default: `shellServedFromCache`). */
|
|
31
|
+
shellFromCache?: () => boolean;
|
|
29
32
|
}
|
|
30
33
|
export declare function pageBuildId(): string;
|
|
34
|
+
/** True when this page's HTML was served from the browser cache without
|
|
35
|
+
* reaching the server. Android Chrome does this when it restores a tab whose
|
|
36
|
+
* renderer it killed in the background, even for a `no-cache` shell, so the
|
|
37
|
+
* restored page can run a build older than current traffic (reader,
|
|
38
|
+
* 2026-09-26/27: 9 of 15 phone page loads). */
|
|
39
|
+
export declare function shellServedFromCache(): boolean;
|
|
31
40
|
export declare class BuildUpdateMonitor {
|
|
32
41
|
private deps;
|
|
33
42
|
private state;
|
|
@@ -40,8 +49,10 @@ export declare class BuildUpdateMonitor {
|
|
|
40
49
|
private appliedRequestNumber;
|
|
41
50
|
private trafficBuild;
|
|
42
51
|
private checkFailure;
|
|
43
|
-
/** When the page last went from hidden to visible
|
|
52
|
+
/** When the page last went from hidden to visible, or was loaded visible
|
|
53
|
+
* from a cached shell (a restored tab is a return in all but name). */
|
|
44
54
|
private returnedAt;
|
|
55
|
+
private restoredFromCache;
|
|
45
56
|
private deferUntilHidden;
|
|
46
57
|
constructor(deps: BuildUpdateDeps);
|
|
47
58
|
getState: () => BuildUpdateState;
|
|
@@ -12,6 +12,19 @@ const LEGACY_BUILD = 'legacy-pre-build-id';
|
|
|
12
12
|
export function pageBuildId() {
|
|
13
13
|
return document.querySelector('meta[name="pw-build-id"]')?.content || 'development';
|
|
14
14
|
}
|
|
15
|
+
/** True when this page's HTML was served from the browser cache without
|
|
16
|
+
* reaching the server. Android Chrome does this when it restores a tab whose
|
|
17
|
+
* renderer it killed in the background, even for a `no-cache` shell, so the
|
|
18
|
+
* restored page can run a build older than current traffic (reader,
|
|
19
|
+
* 2026-09-26/27: 9 of 15 phone page loads). */
|
|
20
|
+
export function shellServedFromCache() {
|
|
21
|
+
const entry = globalThis.performance?.getEntriesByType?.('navigation')[0];
|
|
22
|
+
if (!entry)
|
|
23
|
+
return false;
|
|
24
|
+
if (entry.deliveryType === 'cache')
|
|
25
|
+
return true;
|
|
26
|
+
return entry.transferSize === 0 && entry.decodedBodySize > 0;
|
|
27
|
+
}
|
|
15
28
|
export class BuildUpdateMonitor {
|
|
16
29
|
deps;
|
|
17
30
|
state = { kind: 'current' };
|
|
@@ -24,8 +37,10 @@ export class BuildUpdateMonitor {
|
|
|
24
37
|
appliedRequestNumber = 0;
|
|
25
38
|
trafficBuild = null;
|
|
26
39
|
checkFailure = false;
|
|
27
|
-
/** When the page last went from hidden to visible
|
|
40
|
+
/** When the page last went from hidden to visible, or was loaded visible
|
|
41
|
+
* from a cached shell (a restored tab is a return in all but name). */
|
|
28
42
|
returnedAt = null;
|
|
43
|
+
restoredFromCache = false;
|
|
29
44
|
deferUntilHidden = false;
|
|
30
45
|
constructor(deps) {
|
|
31
46
|
this.deps = deps;
|
|
@@ -41,6 +56,13 @@ export class BuildUpdateMonitor {
|
|
|
41
56
|
this.started = true;
|
|
42
57
|
this.lifecycle += 1;
|
|
43
58
|
this.stopSafety = this.deps.safety.subscribe(() => this.maybeReload());
|
|
59
|
+
// A tab restored from the cache shows whatever build it last loaded; a
|
|
60
|
+
// reload now would replace it just as it appears. Treat it as a return.
|
|
61
|
+
// (A hidden restore needs nothing: its reload is out of sight anyway.)
|
|
62
|
+
if (document.visibilityState === 'visible' && (this.deps.shellFromCache ?? shellServedFromCache)()) {
|
|
63
|
+
this.returnedAt = Date.now();
|
|
64
|
+
this.restoredFromCache = true;
|
|
65
|
+
}
|
|
44
66
|
if (document.visibilityState === 'visible')
|
|
45
67
|
this.startPolling();
|
|
46
68
|
document.addEventListener('visibilitychange', this.onVisibility);
|
|
@@ -145,6 +167,7 @@ export class BuildUpdateMonitor {
|
|
|
145
167
|
pageBuildId: this.deps.currentBuildId,
|
|
146
168
|
observedBuildId: buildId,
|
|
147
169
|
sinceReturnMs: Date.now() - (this.returnedAt ?? Date.now()),
|
|
170
|
+
restoredFromCache: this.restoredFromCache,
|
|
148
171
|
});
|
|
149
172
|
}
|
|
150
173
|
}
|
|
@@ -191,6 +214,7 @@ export class BuildUpdateMonitor {
|
|
|
191
214
|
onVisibility = () => {
|
|
192
215
|
if (document.visibilityState === 'visible') {
|
|
193
216
|
this.returnedAt = Date.now();
|
|
217
|
+
this.restoredFromCache = false;
|
|
194
218
|
this.startPolling();
|
|
195
219
|
void this.checkNow();
|
|
196
220
|
}
|
package/package.json
CHANGED