Проблема с бесконечными обновлениями у pwa приложения в safari
Столкнулся с проблемой бесконечного обновления страницы в сафари. Также, по не известной мне причине, подгружается старый кэш, который должен быть удален уже давно. Приложение использует библиотеку vite-pwa.
vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import { VitePWA } from "vite-plugin-pwa";
// https://vitejs.dev/config/export
const isProd = true;
const defaultData = {
strategies: "injectManifest",
start_url: "/index.html",
injectManifest: {
rollupFormat: "iife",
},
registerType: "autoUpdate",
srcDir: "src",
filename: "sw.ts",
devOptions: {
enabled: true,
type: "module",
},
workbox: {
skipWaiting: true,
clientsClaim: true,
cleanupOutdatedCaches: true,
},
manifest: {
name: "",
short_name: "",
description: "",
start_url: "/",
display: "standalone",
background_color: "#272238",
orientation: "portrait",
related_applications: [
{
platform: "webapp",
url: "https://sandbox.desire.fans/manifest.json",
},
],
url_handlers: [
{
origin: "https://sandbox.desire.fans",
},
],
icons: [
{
src: "/manifest/manifest192.png",
sizes: "192x192",
type: "image/png",
},
{
src: "/manifest/manifest512.png",
sizes: "512x512",
type: "image/png",
purpose: "apple touch icon",
},
{
src: "/manifest/favicon.svg",
sizes: "512x512",
type: "image/png",
purpose: "image/svg",
},
{
src: "/manifest/manifest500.png",
sizes: "144x144",
type: "image/png",
purpose: "maskable",
},
{
src: "/manifest/manifest96.png",
sizes: "96x96",
type: "image/png",
},
{
src: "/manifest/manifest144.png",
sizes: "144x144",
type: "image/png",
},
{
src: "/manifest/manifest512.png",
sizes: "512x512",
type: "image/png",
},
],
},
};
const pwaConfig = isProd ? defaultData : {};
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: undefined,
},
},
},
plugins: [react(), VitePWA(pwaConfig)],
});
sw.ts
// Import Cache Names and ClientClaim module for providing the cache name and taking control of all pages immediately
// @ts-ignore
import { clientsClaim } from "workbox-core";
// Import routing modules for registering routes and setting default and catch handlers
import {
registerRoute,
setCatchHandler,
setDefaultHandler,
} from "workbox-routing";
// Import caching modules for caching strategies
import { NetworkFirst, NetworkOnly, Strategy } from "workbox-strategies";
// Import module for caching precached assets
import type { ManifestEntry } from "workbox-build";
// Give TypeScript the correct global.
declare let self: any;
// Declare type for ExtendableEvent to use in install and activate events
declare type ExtendableEvent = any;
// Access the pre-defined cache names for use in this app
const cacheName = "CACHE_APP-1.0.9";
// Configure the strategy for handling all requests based on the data object
const buildStrategy = (): Strategy => {
return new NetworkFirst({
cacheName,
plugins: [
{
cacheWillUpdate: async ({ request, response }) => {
console.log(request);
if (
!response ||
response.status !== 200 ||
response.type !== "basic"
) {
return null;
}
return response;
},
},
],
});
};
// Retrieve the manifest. First define asynchronous function to retrieve the manifest
const manifest = self.__WB_MANIFEST as Array<ManifestEntry>;
// Array for resources that have been cached by the service worker
const cacheEntries: RequestInfo[] = [];
// Run through the manifest and cache all resources
const manifestURLs = manifest.map((entry) => {
const url = new URL(entry.url, self.location.href);
cacheEntries.push(new Request(url.href, { credentials: "same-origin" }));
return url.href;
});
self.addEventListener("install", (event) => {
const cacheWhitelist = [cacheName];
self.skipWaiting();
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
}),
);
}),
);
});
// Upon activating the service worker, clear outdated caches by removing caches associated with
// URL resources that are not in the manifest URL array
self.addEventListener("activate", (event: ExtendableEvent) => {
const currentCacheName = cacheName;
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cache) => {
if (cache !== currentCacheName) {
return caches.delete(cache);
}
}),
);
}),
);
event.waitUntil(self.clients.claim());
});
// Register all URLs that are found in the manifest and use the buildStrategy function to cache them
registerRoute(({ url }) => manifestURLs.includes(url.href), buildStrategy());
// Inform the service worker to send all routes that are not recognized to the network to be fetched
setDefaultHandler(new NetworkOnly());
// This method is called when the service worker is unable to fetch a resource from the network
setCatchHandler(({ event }: any): Promise<Response> => {
switch (event.request.destination) {
case "document":
return caches.match("/index.html").then((response) => {
return response || Promise.reject("no-match");
});
default:
return Promise.reject("no-match");
}
});