Skip to content

Commit

Permalink
Clear file cache through separate fetch::no-cache call
Browse files Browse the repository at this point in the history
## Issue
ChunkLoadError.

There is anecdote saying that Chromium will cache failed responses (e.g. timeout), so users could end up perpetually in a bad state until the cache is manually cleared, or the site moved on to a new chunk.

`https://github.com/whatwg/html/issues/6768`

## Approach
While there is no way to programmatically clear a user's cache, doing a separate `fetch` with `no-cache` indirectly replaces the cache with a fresh download.
  • Loading branch information
infinite-persistence committed Oct 2, 2023
1 parent 14aa93f commit 28cc837
Showing 1 changed file with 40 additions and 11 deletions.
51 changes: 40 additions & 11 deletions ui/util/lazyImport.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,52 @@
import React from 'react';
import * as ACTIONS from 'constants/action_types';
import { URL as SITE_URL } from 'config';

const RETRY_DELAY_MS = 3000;
const RETRY_ATTEMPTS = 5;
const RETRY_DELAY_MS = 5000;
const RETRY_ATTEMPTS = 4;

/**
* While there is no way to programmatically clear a user's cache, doing a
* separate `fetch` with `no-cache` indirectly replaces the cache with a fresh
* download.
*
* This is an opportunistic attempt which fails silently, as some browsers may
* not return the URL in the error.
*
* @param error ChunkLoadError which contains the URL of the failed webpack import.
* @returns {Promise<void>}
*/
async function bustFileCache(error) {
try {
const match = error?.message?.match(new RegExp(`${SITE_URL}(.+?\\.js)`, 'gi'));
const url = match[0];
await fetch(url, { cache: 'no-cache' });
} catch (err) {
console.error('bustFileCache:', err.message); // eslint-disable-line no-console
}
}

function componentLoader(lazyComponent, attemptsLeft) {
return new Promise((resolve, reject) => {
lazyComponent()
.then(resolve)
.catch((error) => {
setTimeout(() => {
if (attemptsLeft === 1) {
window.store.dispatch({
type: ACTIONS.RELOAD_REQUIRED,
data: { reason: 'lazyImportFailed', extra: error },
});
console.error(error.message); // eslint-disable-line no-console
} else {
componentLoader(lazyComponent, attemptsLeft - 1).then(resolve, reject);
setTimeout(async () => {
switch (attemptsLeft) {
case 0:
window.store.dispatch({
type: ACTIONS.RELOAD_REQUIRED,
data: { reason: 'lazyImportFailed', extra: error },
});
console.error(error.message); // eslint-disable-line no-console
break;

default:
if (attemptsLeft === 1) {
await bustFileCache(error);
}
componentLoader(lazyComponent, attemptsLeft - 1).then(resolve, reject);
break;
}
}, RETRY_DELAY_MS);
});
Expand Down

0 comments on commit 28cc837

Please sign in to comment.