webperf-snippets 0.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 +139 -0
- package/package.json +54 -0
- package/snippets/CoreWebVitals/CLS.js +88 -0
- package/snippets/CoreWebVitals/INP.js +432 -0
- package/snippets/CoreWebVitals/LCP-Image-Entropy.js +198 -0
- package/snippets/CoreWebVitals/LCP-Subparts.js +286 -0
- package/snippets/CoreWebVitals/LCP-Trail.js +184 -0
- package/snippets/CoreWebVitals/LCP-Video-Candidate.js +228 -0
- package/snippets/CoreWebVitals/LCP.js +135 -0
- package/snippets/CoreWebVitals/WORKFLOWS.md +203 -0
- package/snippets/DevTools-Overrides/Fetch-XHR-Timeline-inject.js +73 -0
- package/snippets/DevTools-Overrides/Fetch-XHR-Timeline-read.js +191 -0
- package/snippets/Interaction/Forced-Synchronous-Layout.js +286 -0
- package/snippets/Interaction/Input-Latency-Breakdown.js +199 -0
- package/snippets/Interaction/Interactions.js +220 -0
- package/snippets/Interaction/Layout-Shift-Loading-and-Interaction.js +266 -0
- package/snippets/Interaction/Long-Animation-Frames-Helpers.js +397 -0
- package/snippets/Interaction/Long-Animation-Frames-Script-Attribution.js +137 -0
- package/snippets/Interaction/Long-Animation-Frames.js +298 -0
- package/snippets/Interaction/LongTask.js +203 -0
- package/snippets/Interaction/Scroll-Performance.js +359 -0
- package/snippets/Interaction/WORKFLOWS.md +205 -0
- package/snippets/Loading/Back-Forward-Cache.js +473 -0
- package/snippets/Loading/CSS-Media-Queries-Analysis.js +512 -0
- package/snippets/Loading/Cache-Strategy-Analysis.js +808 -0
- package/snippets/Loading/Client-Side-Redirect-Detection.js +337 -0
- package/snippets/Loading/Content-Visibility.js +352 -0
- package/snippets/Loading/Critical-CSS-Detection.js +329 -0
- package/snippets/Loading/Event-Processing-Time.js +179 -0
- package/snippets/Loading/FCP.js +101 -0
- package/snippets/Loading/Find-Above-The-Fold-Lazy-Loaded-Images.js +264 -0
- package/snippets/Loading/Find-Images-With-Lazy-and-Fetchpriority.js +155 -0
- package/snippets/Loading/Find-non-Lazy-Loaded-Images-outside-of-the-viewport.js +300 -0
- package/snippets/Loading/Find-render-blocking-resources.js +161 -0
- package/snippets/Loading/First-And-Third-Party-Script-Info.js +269 -0
- package/snippets/Loading/First-And-Third-Party-Script-Timings.js +295 -0
- package/snippets/Loading/Fonts-Preloaded-Loaded-and-used-above-the-fold.js +317 -0
- package/snippets/Loading/Inline-CSS-Info-and-Size.js +234 -0
- package/snippets/Loading/Inline-Script-Info-and-Size.js +323 -0
- package/snippets/Loading/JS-Execution-Time-Breakdown.js +336 -0
- package/snippets/Loading/Prefetch-Resource-Validation.js +456 -0
- package/snippets/Loading/Priority-Hints-Audit.js +336 -0
- package/snippets/Loading/Resource-Hints-Validation.js +503 -0
- package/snippets/Loading/Resource-Hints.js +400 -0
- package/snippets/Loading/SSR-Hydration-Data-Analysis.js +364 -0
- package/snippets/Loading/Script-Loading.js +332 -0
- package/snippets/Loading/Service-Worker-Analysis.js +192 -0
- package/snippets/Loading/TTFB-Resources.js +115 -0
- package/snippets/Loading/TTFB-Sub-Parts.js +117 -0
- package/snippets/Loading/TTFB.js +37 -0
- package/snippets/Loading/Validate-Preload-Async-Defer-Scripts.js +394 -0
- package/snippets/Loading/WORKFLOWS.md +163 -0
- package/snippets/Media/Image-Element-Audit.js +350 -0
- package/snippets/Media/SVG-Embedded-Bitmap-Analysis.js +225 -0
- package/snippets/Media/Video-Element-Audit.js +282 -0
- package/snippets/Media/WORKFLOWS.md +190 -0
- package/snippets/README.md +98 -0
- package/snippets/Resources/Network-Bandwidth-Connection-Quality.js +103 -0
- package/snippets/Resources/WORKFLOWS.md +173 -0
- package/src/bin.js +229 -0
- package/src/decision-tree.js +19 -0
- package/src/load-snippet.js +23 -0
- package/src/reporters/human.js +179 -0
- package/src/reporters/json.js +3 -0
- package/src/runner.js +61 -0
- package/src/workflows/audit.js +21 -0
- package/src/workflows/cwv.js +10 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
// Back/Forward Cache (bfcache) Analysis
|
|
2
|
+
// https://webperf-snippets.nucliweb.net
|
|
3
|
+
|
|
4
|
+
(() => {
|
|
5
|
+
const results = {
|
|
6
|
+
supported: 'PerformanceNavigationTiming' in window,
|
|
7
|
+
wasRestored: false,
|
|
8
|
+
eligibility: null,
|
|
9
|
+
blockingReasons: [],
|
|
10
|
+
recommendations: [],
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
// Check if current page was restored from bfcache
|
|
14
|
+
const checkRestoration = () => {
|
|
15
|
+
// Check via pageshow event
|
|
16
|
+
window.addEventListener('pageshow', (event) => {
|
|
17
|
+
if (event.persisted) {
|
|
18
|
+
results.wasRestored = true;
|
|
19
|
+
console.log(
|
|
20
|
+
'%c⚡ Page restored from bfcache!',
|
|
21
|
+
'color: #22c55e; font-weight: bold; font-size: 14px;'
|
|
22
|
+
);
|
|
23
|
+
console.log(' Navigation was instant (0ms)');
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
// Check via Performance Navigation Timing
|
|
28
|
+
if (results.supported) {
|
|
29
|
+
const navEntry = performance.getEntriesByType('navigation')[0];
|
|
30
|
+
if (navEntry && navEntry.type === 'back_forward') {
|
|
31
|
+
// Check activation timing for bfcache restore
|
|
32
|
+
if (navEntry.activationStart > 0) {
|
|
33
|
+
results.wasRestored = true;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
// Test bfcache eligibility
|
|
40
|
+
const testEligibility = () => {
|
|
41
|
+
const issues = [];
|
|
42
|
+
const recs = [];
|
|
43
|
+
|
|
44
|
+
// 1. Check for unload handlers
|
|
45
|
+
const hasUnload = window.onunload !== null || window.onbeforeunload !== null;
|
|
46
|
+
if (hasUnload) {
|
|
47
|
+
issues.push({
|
|
48
|
+
reason: 'unload/beforeunload handler detected',
|
|
49
|
+
severity: 'high',
|
|
50
|
+
description: 'These handlers block bfcache',
|
|
51
|
+
});
|
|
52
|
+
recs.push('Remove unload/beforeunload handlers. Use pagehide or visibilitychange instead.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. Check for Cache-Control: no-store
|
|
56
|
+
// Note: Can't check response headers from JS, but we can detect it indirectly
|
|
57
|
+
const meta = document.querySelector('meta[http-equiv="Cache-Control"]');
|
|
58
|
+
if (meta && meta.content.includes('no-store')) {
|
|
59
|
+
issues.push({
|
|
60
|
+
reason: 'Cache-Control: no-store in meta tag',
|
|
61
|
+
severity: 'high',
|
|
62
|
+
description: 'Prevents page from being cached',
|
|
63
|
+
});
|
|
64
|
+
recs.push('Remove Cache-Control: no-store or change to no-cache.');
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// 3. Check for open IndexedDB connections
|
|
68
|
+
if (window.indexedDB) {
|
|
69
|
+
// Can't directly check open connections, but we can warn
|
|
70
|
+
const hasIndexedDB = performance.getEntriesByType('resource').some(
|
|
71
|
+
r => r.name.includes('indexedDB')
|
|
72
|
+
);
|
|
73
|
+
if (hasIndexedDB) {
|
|
74
|
+
issues.push({
|
|
75
|
+
reason: 'IndexedDB may be in use',
|
|
76
|
+
severity: 'medium',
|
|
77
|
+
description: 'Open IndexedDB transactions block bfcache',
|
|
78
|
+
});
|
|
79
|
+
recs.push('Close IndexedDB connections before page hide.');
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// 4. Check for broadcast channels
|
|
84
|
+
// Can't directly detect, but can check if BroadcastChannel exists
|
|
85
|
+
if (window.BroadcastChannel) {
|
|
86
|
+
// Just a warning - we can't detect if actually in use
|
|
87
|
+
issues.push({
|
|
88
|
+
reason: 'BroadcastChannel API available (check if in use)',
|
|
89
|
+
severity: 'low',
|
|
90
|
+
description: 'Open BroadcastChannel connections may block bfcache',
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// 5. Check for embedded iframes with issues
|
|
95
|
+
const iframes = document.querySelectorAll('iframe');
|
|
96
|
+
if (iframes.length > 0) {
|
|
97
|
+
issues.push({
|
|
98
|
+
reason: `${iframes.length} iframe(s) detected`,
|
|
99
|
+
severity: 'medium',
|
|
100
|
+
description: 'Iframes with bfcache blockers will block parent page',
|
|
101
|
+
});
|
|
102
|
+
recs.push('Ensure iframes are also bfcache compatible.');
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// 6. Check for Service Worker
|
|
106
|
+
if ('serviceWorker' in navigator && navigator.serviceWorker.controller) {
|
|
107
|
+
// Service workers are OK, but just noting it
|
|
108
|
+
issues.push({
|
|
109
|
+
reason: 'Service Worker active',
|
|
110
|
+
severity: 'info',
|
|
111
|
+
description: 'Service Workers with fetch handlers are generally OK, but check for ongoing operations',
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// 7. Check for open WebSocket/WebRTC
|
|
116
|
+
// Can't directly detect, but we can check for common libraries
|
|
117
|
+
if (window.WebSocket) {
|
|
118
|
+
issues.push({
|
|
119
|
+
reason: 'WebSocket API available (check if connections are open)',
|
|
120
|
+
severity: 'medium',
|
|
121
|
+
description: 'Open WebSocket connections block bfcache',
|
|
122
|
+
});
|
|
123
|
+
recs.push('Close WebSocket connections before page hide.');
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// 8. Check for ongoing fetch/XHR
|
|
127
|
+
// Check if there are active resource requests
|
|
128
|
+
const resources = performance.getEntriesByType('resource');
|
|
129
|
+
const recent = resources.filter(r => r.responseEnd === 0 || (performance.now() - r.responseEnd < 100));
|
|
130
|
+
if (recent.length > 0) {
|
|
131
|
+
issues.push({
|
|
132
|
+
reason: `${recent.length} recent/ongoing network requests`,
|
|
133
|
+
severity: 'low',
|
|
134
|
+
description: 'Ongoing requests may prevent bfcache',
|
|
135
|
+
});
|
|
136
|
+
recs.push('Ensure requests complete or are aborted on page hide.');
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
results.blockingReasons = issues;
|
|
140
|
+
results.recommendations = recs;
|
|
141
|
+
|
|
142
|
+
// Determine eligibility
|
|
143
|
+
const highSeverity = issues.filter(i => i.severity === 'high').length;
|
|
144
|
+
const mediumSeverity = issues.filter(i => i.severity === 'medium').length;
|
|
145
|
+
|
|
146
|
+
if (highSeverity > 0) {
|
|
147
|
+
results.eligibility = 'blocked';
|
|
148
|
+
} else if (mediumSeverity > 1) {
|
|
149
|
+
results.eligibility = 'likely-blocked';
|
|
150
|
+
} else if (issues.length > 0) {
|
|
151
|
+
results.eligibility = 'potentially-eligible';
|
|
152
|
+
} else {
|
|
153
|
+
results.eligibility = 'likely-eligible';
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return results.eligibility;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
// Display results
|
|
160
|
+
const displayResults = () => {
|
|
161
|
+
const statusIcons = {
|
|
162
|
+
'likely-eligible': '🟢',
|
|
163
|
+
'potentially-eligible': '🟡',
|
|
164
|
+
'likely-blocked': '🟠',
|
|
165
|
+
'blocked': '🔴',
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
const statusColors = {
|
|
169
|
+
'likely-eligible': '#22c55e',
|
|
170
|
+
'potentially-eligible': '#f59e0b',
|
|
171
|
+
'likely-blocked': '#fb923c',
|
|
172
|
+
'blocked': '#ef4444',
|
|
173
|
+
};
|
|
174
|
+
|
|
175
|
+
const statusText = {
|
|
176
|
+
'likely-eligible': 'Likely Eligible',
|
|
177
|
+
'potentially-eligible': 'Potentially Eligible',
|
|
178
|
+
'likely-blocked': 'Likely Blocked',
|
|
179
|
+
'blocked': 'Blocked',
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
const icon = statusIcons[results.eligibility] || '⚪';
|
|
183
|
+
const color = statusColors[results.eligibility] || '#6b7280';
|
|
184
|
+
const text = statusText[results.eligibility] || 'Unknown';
|
|
185
|
+
|
|
186
|
+
console.group(
|
|
187
|
+
`%c${icon} bfcache Status: ${text}`,
|
|
188
|
+
`color: ${color}; font-weight: bold; font-size: 14px;`
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
console.log('');
|
|
192
|
+
console.log('%c📊 Status:', 'font-weight: bold;');
|
|
193
|
+
|
|
194
|
+
if (results.wasRestored) {
|
|
195
|
+
console.log('%c ✅ This page WAS restored from bfcache', 'color: #22c55e;');
|
|
196
|
+
console.log(' Navigation was instant!');
|
|
197
|
+
} else {
|
|
198
|
+
console.log(' ℹ️ This page was NOT restored from bfcache');
|
|
199
|
+
console.log(' (Either first visit or bfcache was blocked on previous navigation)');
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Navigation timing comparison
|
|
203
|
+
if (results.supported) {
|
|
204
|
+
const navEntry = performance.getEntriesByType('navigation')[0];
|
|
205
|
+
if (navEntry) {
|
|
206
|
+
console.log('');
|
|
207
|
+
console.log('%c🕐 Navigation Timing:', 'font-weight: bold;');
|
|
208
|
+
console.log(` Type: ${navEntry.type}`);
|
|
209
|
+
console.log(` Duration: ${Math.round(navEntry.duration)}ms`);
|
|
210
|
+
|
|
211
|
+
if (navEntry.type === 'back_forward') {
|
|
212
|
+
if (navEntry.duration < 10) {
|
|
213
|
+
console.log('%c ⚡ Fast back/forward (likely from bfcache)', 'color: #22c55e;');
|
|
214
|
+
} else {
|
|
215
|
+
console.log('%c 🐌 Slow back/forward (full reload)', 'color: #ef4444;');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// Display issues
|
|
222
|
+
if (results.blockingReasons.length > 0) {
|
|
223
|
+
console.log('');
|
|
224
|
+
console.log('%c🔍 Potential Issues:', 'font-weight: bold;');
|
|
225
|
+
|
|
226
|
+
const issueTable = results.blockingReasons.map(issue => ({
|
|
227
|
+
Severity: issue.severity.toUpperCase(),
|
|
228
|
+
Issue: issue.reason,
|
|
229
|
+
Impact: issue.description,
|
|
230
|
+
}));
|
|
231
|
+
|
|
232
|
+
console.table(issueTable);
|
|
233
|
+
} else {
|
|
234
|
+
console.log('');
|
|
235
|
+
console.log('%c✅ No obvious bfcache blockers detected!', 'color: #22c55e; font-weight: bold;');
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// Recommendations
|
|
239
|
+
if (results.recommendations.length > 0) {
|
|
240
|
+
console.log('');
|
|
241
|
+
console.log('%c💡 Recommendations:', 'color: #3b82f6; font-weight: bold;');
|
|
242
|
+
results.recommendations.forEach((rec, idx) => {
|
|
243
|
+
console.log(` ${idx + 1}. ${rec}`);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
// How to test
|
|
248
|
+
console.log('');
|
|
249
|
+
console.log('%c🧪 How to Test:', 'font-weight: bold;');
|
|
250
|
+
console.log('%c IMPORTANT: Run snippet BEFORE navigating away!', 'color: #f59e0b;');
|
|
251
|
+
console.log('');
|
|
252
|
+
console.log(' 1. Run this snippet (you already did this ✓)');
|
|
253
|
+
console.log(' 2. Navigate to another page');
|
|
254
|
+
console.log(' 3. Click browser Back button');
|
|
255
|
+
console.log(' 4. Check console for restoration message');
|
|
256
|
+
console.log('');
|
|
257
|
+
console.log(' Or use Chrome DevTools → Application → Back/forward cache');
|
|
258
|
+
|
|
259
|
+
console.groupEnd();
|
|
260
|
+
|
|
261
|
+
return results;
|
|
262
|
+
};
|
|
263
|
+
|
|
264
|
+
// Check for NotRestoredReasons API (Chrome 123+)
|
|
265
|
+
const checkNotRestoredReasons = () => {
|
|
266
|
+
if (!('PerformanceNavigationTiming' in window)) {
|
|
267
|
+
return null;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
const navEntry = performance.getEntriesByType('navigation')[0];
|
|
271
|
+
if (!navEntry || !navEntry.notRestoredReasons) {
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
console.group('%c🔬 Not Restored Reasons (Chrome 123+)', 'font-weight: bold; color: #3b82f6;');
|
|
276
|
+
|
|
277
|
+
const reasons = navEntry.notRestoredReasons;
|
|
278
|
+
|
|
279
|
+
console.log('');
|
|
280
|
+
console.log('%cPage-level information:', 'font-weight: bold;');
|
|
281
|
+
|
|
282
|
+
if (reasons.blocked === true) {
|
|
283
|
+
console.log('%c ❌ Page was blocked from bfcache', 'color: #ef4444;');
|
|
284
|
+
} else {
|
|
285
|
+
console.log('%c ✅ Page was not blocked', 'color: #22c55e;');
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (reasons.url) {
|
|
289
|
+
console.log(` URL: ${reasons.url}`);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (reasons.id) {
|
|
293
|
+
console.log(` Frame ID: ${reasons.id}`);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
if (reasons.name) {
|
|
297
|
+
console.log(` Frame name: ${reasons.name}`);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
if (reasons.src) {
|
|
301
|
+
console.log(` Source: ${reasons.src}`);
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// Parse NotRestoredReasonDetails array
|
|
305
|
+
// Each entry is an object with { reason: string, source: string }
|
|
306
|
+
// Common reasons: "WebSocket", "unload-listener", "IndexedDB", etc.
|
|
307
|
+
// Sources: "JavaScript", "UserAgentOnly", etc.
|
|
308
|
+
if (reasons.reasons && reasons.reasons.length > 0) {
|
|
309
|
+
console.log('');
|
|
310
|
+
console.log('%cBlocking reasons:', 'font-weight: bold; color: #ef4444;');
|
|
311
|
+
|
|
312
|
+
reasons.reasons.forEach((reasonDetail, idx) => {
|
|
313
|
+
// reasonDetail is a NotRestoredReasonDetails object
|
|
314
|
+
const reasonName = reasonDetail.reason || 'Unknown reason';
|
|
315
|
+
const reasonSource = reasonDetail.source || 'Unknown source';
|
|
316
|
+
|
|
317
|
+
console.group(` ${idx + 1}. ${reasonName}`);
|
|
318
|
+
|
|
319
|
+
// Show detailed information
|
|
320
|
+
console.log(` Reason: ${reasonName}`);
|
|
321
|
+
console.log(` Source: ${reasonSource}`);
|
|
322
|
+
|
|
323
|
+
// Add helpful context for common reasons
|
|
324
|
+
const reasonExplanations = {
|
|
325
|
+
'WebSocket': 'Open WebSocket connections prevent bfcache. Close them on pagehide event.',
|
|
326
|
+
'unload-listener': 'unload event listeners block bfcache. Use pagehide or visibilitychange instead.',
|
|
327
|
+
'response-cache-control-no-store': 'Cache-Control: no-store header prevents caching. Change to no-cache.',
|
|
328
|
+
'IndexedDB': 'Open IndexedDB transactions block bfcache. Close connections on pagehide.',
|
|
329
|
+
'BroadcastChannel': 'Open BroadcastChannel prevents bfcache. Close it on pagehide.',
|
|
330
|
+
'dedicated-worker': 'Dedicated workers can block bfcache. Terminate them on pagehide.',
|
|
331
|
+
};
|
|
332
|
+
|
|
333
|
+
if (reasonExplanations[reasonName]) {
|
|
334
|
+
console.log(` 💡 ${reasonExplanations[reasonName]}`);
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
console.groupEnd();
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
// Check children (iframes)
|
|
342
|
+
if (reasons.children && reasons.children.length > 0) {
|
|
343
|
+
console.log('');
|
|
344
|
+
console.log('%cEmbedded frames:', 'font-weight: bold;');
|
|
345
|
+
|
|
346
|
+
reasons.children.forEach((child, idx) => {
|
|
347
|
+
console.group(` ${idx + 1}. ${child.url || child.src || 'iframe'}`);
|
|
348
|
+
|
|
349
|
+
if (child.blocked) {
|
|
350
|
+
console.log('%c Status: BLOCKED', 'color: #ef4444;');
|
|
351
|
+
} else {
|
|
352
|
+
console.log('%c Status: OK', 'color: #22c55e;');
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (child.id) {
|
|
356
|
+
console.log(` Frame ID: ${child.id}`);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (child.name) {
|
|
360
|
+
console.log(` Frame name: ${child.name}`);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
if (child.reasons && child.reasons.length > 0) {
|
|
364
|
+
console.log(' Blocking reasons:');
|
|
365
|
+
child.reasons.forEach(reasonDetail => {
|
|
366
|
+
console.log(` • ${reasonDetail.reason || 'Unknown'}`);
|
|
367
|
+
if (reasonDetail.source) {
|
|
368
|
+
console.log(` Source: ${reasonDetail.source}`);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
console.groupEnd();
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// Summary table for easier visualization
|
|
378
|
+
if (reasons.reasons && reasons.reasons.length > 0) {
|
|
379
|
+
console.log('');
|
|
380
|
+
console.log('%c📋 Summary Table:', 'font-weight: bold;');
|
|
381
|
+
|
|
382
|
+
const reasonsTable = reasons.reasons.map(r => ({
|
|
383
|
+
Reason: r.reason || 'Unknown',
|
|
384
|
+
Source: r.source || 'N/A',
|
|
385
|
+
}));
|
|
386
|
+
|
|
387
|
+
console.table(reasonsTable);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
console.groupEnd();
|
|
391
|
+
return reasons;
|
|
392
|
+
};
|
|
393
|
+
|
|
394
|
+
// Check if snippet was executed after a back/forward navigation
|
|
395
|
+
const checkExecutionTiming = () => {
|
|
396
|
+
const navEntry = performance.getEntriesByType('navigation')[0];
|
|
397
|
+
if (navEntry && navEntry.type === 'back_forward') {
|
|
398
|
+
console.log('');
|
|
399
|
+
console.group('%c⚠️ Timing Warning', 'color: #f59e0b; font-weight: bold;');
|
|
400
|
+
console.log('%cSnippet executed AFTER back/forward navigation.', 'color: #f59e0b;');
|
|
401
|
+
console.log('');
|
|
402
|
+
console.log('For complete analysis including bfcache restoration detection:');
|
|
403
|
+
console.log(' 1. Run this snippet FIRST');
|
|
404
|
+
console.log(' 2. Then navigate away');
|
|
405
|
+
console.log(' 3. Then click Back button');
|
|
406
|
+
console.log('');
|
|
407
|
+
console.log('Current analysis shows NotRestoredReasons from the navigation that just occurred.');
|
|
408
|
+
console.groupEnd();
|
|
409
|
+
console.log('');
|
|
410
|
+
}
|
|
411
|
+
};
|
|
412
|
+
|
|
413
|
+
// Initialize
|
|
414
|
+
checkRestoration();
|
|
415
|
+
testEligibility();
|
|
416
|
+
|
|
417
|
+
// Display after a short delay to ensure pageshow event fires
|
|
418
|
+
setTimeout(() => {
|
|
419
|
+
checkExecutionTiming();
|
|
420
|
+
displayResults();
|
|
421
|
+
|
|
422
|
+
// Check NotRestoredReasons API if available
|
|
423
|
+
const notRestoredReasons = checkNotRestoredReasons();
|
|
424
|
+
if (!notRestoredReasons) {
|
|
425
|
+
console.log('');
|
|
426
|
+
console.log('%cℹ️ For detailed reasons, use Chrome 123+ and navigate back to this page.', 'color: #6b7280;');
|
|
427
|
+
}
|
|
428
|
+
}, 100);
|
|
429
|
+
|
|
430
|
+
// Expose function for manual check
|
|
431
|
+
window.checkBfcache = () => {
|
|
432
|
+
testEligibility();
|
|
433
|
+
displayResults();
|
|
434
|
+
checkNotRestoredReasons();
|
|
435
|
+
return {
|
|
436
|
+
script: "Back-Forward-Cache",
|
|
437
|
+
status: "ok",
|
|
438
|
+
details: {
|
|
439
|
+
eligibility: results.eligibility,
|
|
440
|
+
wasRestored: results.wasRestored,
|
|
441
|
+
supported: results.supported,
|
|
442
|
+
},
|
|
443
|
+
issues: results.blockingReasons.map(i => ({
|
|
444
|
+
severity: i.severity === 'high' ? 'error' : i.severity === 'medium' ? 'warning' : 'info',
|
|
445
|
+
message: i.reason,
|
|
446
|
+
})),
|
|
447
|
+
};
|
|
448
|
+
};
|
|
449
|
+
|
|
450
|
+
console.log('%c🚀 bfcache Analysis Running...', 'font-weight: bold; font-size: 14px;');
|
|
451
|
+
console.log(' Results will appear shortly.');
|
|
452
|
+
console.log(
|
|
453
|
+
' Call %ccheckBfcache()%c anytime to re-run analysis.',
|
|
454
|
+
'font-family: monospace; background: #f3f4f6; padding: 2px 4px;',
|
|
455
|
+
''
|
|
456
|
+
);
|
|
457
|
+
|
|
458
|
+
return {
|
|
459
|
+
script: "Back-Forward-Cache",
|
|
460
|
+
status: "ok",
|
|
461
|
+
details: {
|
|
462
|
+
eligibility: results.eligibility,
|
|
463
|
+
wasRestored: results.wasRestored,
|
|
464
|
+
supported: results.supported,
|
|
465
|
+
},
|
|
466
|
+
issues: results.blockingReasons.map(i => ({
|
|
467
|
+
severity: i.severity === 'high' ? 'error' : i.severity === 'medium' ? 'warning' : 'info',
|
|
468
|
+
message: i.reason,
|
|
469
|
+
})),
|
|
470
|
+
message: "bfcache analysis running. Call checkBfcache() to re-run analysis.",
|
|
471
|
+
getDataFn: "checkBfcache",
|
|
472
|
+
};
|
|
473
|
+
})();
|