Кэширование страниц 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 на скриптах

Кажется, что я точно что-то не так делаю и все только усложняю. Может есть тут те, кто сталкивался с таким кейсом и знает как правильно обработать такие запросы?


Ответы (0 шт):