fix(docs-infra): print info to help debugging SW cache issue (#41106)
From time to time, an angular.io page fails to load due to requesting a file that cannot be found neither on the server nor in the cache. We believe this is caused by the browser's partially clearing a cache. See #28114 for more details. Some time ago, we introduced [SwUpdate#unrecoverable][1] to help work around this issue by [reloading the page][2] when such an error is detected. However, this issue still pops up occasionally (for example, #41073). In an attempt to help diagnose the issue, this commit prints more info regarding the SW state and cache content when this error occurs. It will result in something like the following being printed to the console: ``` ServiceWorker: activated Cache: ngsw:/:db:control (2 entries) - https://angular.io/assignments: {"f5f02035-ee1f-463c-946c-e8b85badca25":"5c95f89a85255a6fefb4045a20f751ef32b2f3a4"} - https://angular.io/latest: {"latest":"5c95f89a85255a6fefb4045a20f751ef32b2f3a4"} Cache: ngsw:/:5c95f89a85255a6fefb4045a20f751ef32b2f3a4:assets:app-shell:cache (24 entries) - https://angular.io/0-es2015.867022f8bb092ae1efb1.worker.js - https://angular.io/announcement-bar-announcement-bar-module-es2015.1b5b762c9c8837c770f8.js - https://angular.io/api-api-list-module-es2015.40a43cd22f50f64d63bb.js ... Cache: ngsw:/:db:ngsw:/:5c95f89a85255a6fefb4045a20f751ef32b2f3a4:assets:app-shell:meta (1 entries) - https://angular.io/https://fonts.gstatic.com/s/robotomono/v13/L0x5DF4xlVMF-BfR8bXMIjhLq3-cXbKD.woff2: {"ts":1615031956601,"used":true} If you see this error, please report an issue at https://github.com/angular/angular/issues/new?template=3-docs-bug.md including the above logs. ``` NOTE: This change increases the main bundle by 1649B (0.37%), but it can be reverted as soon as we gather enough info to diagnose the issue. [1]: https://angular.io/api/service-worker/SwUpdate#unrecoverable [2]: https://github.com/angular/angular/blob/c676ec1ce5d586d4bc46/aio/src/app/sw-updates/sw-updates.service.ts#L55-L61 PR Close #41106
This commit is contained in:
parent
7a27cd262f
commit
f281310d39
|
@ -143,10 +143,18 @@ export class DocViewerComponent implements OnDestroy {
|
||||||
switchMap(() => this.swapViews(addTitleAndToc)),
|
switchMap(() => this.swapViews(addTitleAndToc)),
|
||||||
tap(() => this.docRendered.emit()),
|
tap(() => this.docRendered.emit()),
|
||||||
catchError(err => {
|
catchError(err => {
|
||||||
const errorMessage = (err instanceof Error) ? err.stack : err;
|
const errorMessage = `${(err instanceof Error) ? err.stack : err}`;
|
||||||
this.logger.error(new Error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`));
|
this.logger.error(new Error(`[DocViewer] Error preparing document '${doc.id}': ${errorMessage}`));
|
||||||
this.nextViewContainer.innerHTML = '';
|
this.nextViewContainer.innerHTML = '';
|
||||||
this.setNoIndex(true);
|
this.setNoIndex(true);
|
||||||
|
|
||||||
|
// TODO(gkalpak): Remove this once gathering debug info is no longer needed.
|
||||||
|
if (/loading chunk \d+ failed/i.test(errorMessage)) {
|
||||||
|
// Print some info to help with debugging.
|
||||||
|
// (There is no reason to wait for this async call to complete before continuing.)
|
||||||
|
printSwDebugInfo();
|
||||||
|
}
|
||||||
|
|
||||||
return this.void$;
|
return this.void$;
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -244,3 +252,63 @@ export class DocViewerComponent implements OnDestroy {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Helpers
|
||||||
|
/**
|
||||||
|
* Print some info regarding the ServiceWorker and the caches contents to help debugging potential
|
||||||
|
* issues with failing to find resources in the cache.
|
||||||
|
* (See https://github.com/angular/angular/issues/28114.)
|
||||||
|
*/
|
||||||
|
async function printSwDebugInfo(): Promise<void> {
|
||||||
|
console.log(`\nServiceWorker: ${navigator.serviceWorker?.controller?.state ?? 'N/A'}`);
|
||||||
|
|
||||||
|
if (typeof caches === 'undefined') {
|
||||||
|
console.log('\nCaches: N/A');
|
||||||
|
} else {
|
||||||
|
const allCacheNames = await caches.keys();
|
||||||
|
const swCacheNames = allCacheNames.filter(name => name.startsWith('ngsw:/:'));
|
||||||
|
|
||||||
|
await findCachesAndPrintEntries(swCacheNames, 'db:control', true, ['manifests']);
|
||||||
|
await findCachesAndPrintEntries(swCacheNames, 'assets:app-shell:cache', false);
|
||||||
|
await findCachesAndPrintEntries(swCacheNames, 'assets:app-shell:meta', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
console.warn(
|
||||||
|
'\nIf you see this error, please report an issue at ' +
|
||||||
|
'https://github.com/angular/angular/issues/new?template=3-docs-bug.md including the above logs.');
|
||||||
|
|
||||||
|
// Internal helpers
|
||||||
|
async function findCachesAndPrintEntries(
|
||||||
|
swCacheNames: string[], nameSuffix: string, includeValues: boolean,
|
||||||
|
ignoredKeys: string[] = []): Promise<void> {
|
||||||
|
const cacheNames = swCacheNames.filter(name => name.endsWith(nameSuffix));
|
||||||
|
|
||||||
|
for (const cacheName of cacheNames) {
|
||||||
|
const cacheEntries = await getCacheEntries(cacheName, includeValues, ignoredKeys);
|
||||||
|
await printCacheEntries(cacheName, cacheEntries);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getCacheEntries(
|
||||||
|
name: string, includeValues: boolean,
|
||||||
|
ignoredKeys: string[] = []): Promise<{key: string, value?: object}[]> {
|
||||||
|
const ignoredUrls = new Set(ignoredKeys.map(key => new Request(key).url));
|
||||||
|
|
||||||
|
const cache = await caches.open(name);
|
||||||
|
const keys = (await cache.keys()).map(req => req.url).filter(url => !ignoredUrls.has(url));
|
||||||
|
const entries = await Promise.all(keys.map(async key => ({
|
||||||
|
key,
|
||||||
|
value: !includeValues ? undefined : await (await cache.match(key))?.json(),
|
||||||
|
})));
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
function printCacheEntries(name: string, entries: {key: string, value?: object}[]): void {
|
||||||
|
const entriesStr = entries
|
||||||
|
.map(({key, value}) => ` - ${key}${!value ? '' : `: ${JSON.stringify(value)}`}`)
|
||||||
|
.join('\n');
|
||||||
|
|
||||||
|
console.log(`\nCache: ${name} (${entries.length} entries)\n${entriesStr}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 3033,
|
"runtime-es2015": 3033,
|
||||||
"main-es2015": 449310,
|
"main-es2015": 450953,
|
||||||
"polyfills-es2015": 52343
|
"polyfills-es2015": 52343
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 3033,
|
"runtime-es2015": 3033,
|
||||||
"main-es2015": 449759,
|
"main-es2015": 451402,
|
||||||
"polyfills-es2015": 52493
|
"polyfills-es2015": 52493
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
"master": {
|
"master": {
|
||||||
"uncompressed": {
|
"uncompressed": {
|
||||||
"runtime-es2015": 3153,
|
"runtime-es2015": 3153,
|
||||||
"main-es2015": 435362,
|
"main-es2015": 437005,
|
||||||
"polyfills-es2015": 52493
|
"polyfills-es2015": 52493
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue