Кэширование страниц React Router с помощью Workbox
В моем проекте используется Service Worker + React Router + Workbox. Проблема в том, что пути у меня фейковые, а вот кэширование настоящее.
Пример:
- Зашел на сайт.
- Network грузит документ - /
- Кэш сохранил и в след раз вернет его, а не будет грузить снова
- Перезагрузил страницу
- Network грузит документ - /
- Отключил сеть
- Перешел на путь итема /item/{hash}
- Ошибка, что нет такого кэша
Что получается: путь / и /item/{hash} иметь один и тот же html код, но если перезагрузить страницу не на корневом пути, то браузер считает этот путь за новый документ, что логично. Но как в этом случае правильно закэшировать эти страницы?
registerRoute(
({ request }) => request.destination === 'document',
async (event) => {
const remote = await respondWithCache('/');
console.log("[WBox Document] respondWithCache", remote.ok);
if (remote.ok) return remote;
console.log("[WBox Document] Else remote");
return fetch(event.request);
}
);
const respondWithCache = async (request) => {
console.log("[WBox Document respondWithCache] cacheResult", request);
const cacheResult = await withTimeout(async () => {
const cache = await self.caches.open(NAMES.STATIC);
const cached = await cache.match(request);
return {cache, cached};
}, 3000);
console.log("[WBox Document respondWithCache] cacheResult", cacheResult);
const {cache, cached} = cacheResult || {};
if (cache && cached) {
if (cached.ok || cached.type === 'opaque') {
return cached;
} else {
await cache.delete(request);
}
}
console.log("[WBox Document respondWithCache] remote fetch", cacheResult);
const remote = await fetch(request, typeof request !== 'string' ? {
headers: request.headers,
mode: request.mode,
method: request.method,
credentials: request.credentials,
referrer: request.referrer,
referrerPolicy: request.referrerPolicy
} : undefined);
if ((remote.ok || remote.type === 'opaque') && cache) {
cache.put(request, remote.clone());
}
return remote;
}
const withTimeout = async (cb, timeout) => {
let isResolved = false;
try {
return await Promise.race([
pause(timeout).then(() => (isResolved ? undefined : Promise.reject(new Error('TIMEOUT')))),
cb(),
]);
} catch (err) {
// eslint-disable-next-line no-console
console.error(err);
return undefined;
} finally {
isResolved = true;
}
}
const pause = (ms) => new Promise((resolve) => self.setTimeout(() => resolve(), ms));
Я пробовал делать вот так. Я игнорирую пути и всегда запрашиваю только корневой путь, но и тут не вылезло без багов. Иногда у пользователей возникает белый экран. Не грузится фронт из-за того, что он устарел.
Получается так:
- Пользователь зашел на страницу из кэша
- Воркер удалил старый кэш
- Воркер сохранил старую страницу как новый кэш
- Воркер пытается польчить скрипты по старым путям и названиям
- У пользователя белый экран и 404 на скриптах
Кажется, что я точно что-то не так делаю и все только усложняю. Может есть тут те, кто сталкивался с таким кейсом и знает как правильно обработать такие запросы?