Estoy atascado en un problema: quería hacer algunas pruebas tratando de convertir mi aplicación web de matraz simple en una aplicación web progresiva, aunque encontré poca información al respecto. Esta es la estructura de mi proyecto:
│ __init__.py │ ├───blueprints │ index.py │ pwa.py │ __init__.py │ ├───static │ │ app.js │ │ manifest.json │ │ offline.html │ │ sw.js │ │ │ └───images │ └───icons │ └───templates index.html layout.html other.htmlEn qué parte del trabajador del servicio hice este archivo basado en el ejemplo de Heroku:
aplicación.js
if (!navigator.serviceWorker.controller) { navigator.serviceWorker.register("/sw.js").then(function (reg) { console.log("Service worker has been registered for scope: " + reg.scope); }); }sw.js
self.addEventListener("install", function (event) { event.waitUntil(preLoad()); }); const preLoad = async function () { console.log("Installing web app"); const cache = await caches.open("offline"); console.log("caching index and important routes"); return await cache.addAll(["/", "static/offline.html"]); }; self.addEventListener("fetch", function (event) { event.respondWith(checkResponse(event.request).catch(function () { return returnFromCache(event.request); })); event.waitUntil(addToCache(event.request)); }); const checkResponse = function (request) { return new Promise(function (fulfill, reject) { fetch(request).then(function (response) { if (response.status !== 404) { fulfill(response); } else { reject(); } }, reject); }); }; const addToCache = async function (request) { const cache = await caches.open("offline"); const response = await fetch(request); console.log(response.url + " was cached"); return await cache.put(request, response); }; const returnFromCache = async function (request) { const cache = await caches.open("offline"); const matching = await cache.match(request); if (!matching || matching.status === 404) { return cache.match("offline.html"); } else { return matching; } };Sin embargo, no entiendo por qué si me desconecto y trato de volver a cargar la aplicación web o la PWA, solo se carga el índice, mientras que solo quiero cargar la página de la plantilla sin conexión, por lo tanto, creo que se almacena en caché, para cargar
Hay un ejemplo de cómo crear una página de respaldo sin conexión dedicada en esta publicación .
Si todo lo que le importa es mostrar una página alternativa fuera de línea, el punto más importante es asegurarse de que solo active su lógica alternativa y llame a event.respondWith() si el controlador de fetch está tratando con una solicitud de navegación. Aquí hay un fragmento de código relevante de esa publicación:
// Incrementing OFFLINE_VERSION will kick off the install event and force // previously cached resources to be updated from the network. // This variable is intentionally declared and unused. const OFFLINE_VERSION = 1; const CACHE_NAME = "offline"; // Customize this with a different URL if needed. const OFFLINE_URL = "offline.html"; self.addEventListener("install", (event) => { event.waitUntil( (async () => { const cache = await caches.open(CACHE_NAME); // Setting {cache: 'reload'} in the new request will ensure that the // response isn't fulfilled from the HTTP cache; ie, it will be from // the network. await cache.add(new Request(OFFLINE_URL, { cache: "reload" })); })() ); // Force the waiting service worker to become the active service worker. self.skipWaiting(); }); self.addEventListener("activate", (event) => { event.waitUntil( (async () => { // Enable navigation preload if it's supported. // See https://developers.google.com/web/updates/2017/02/navigation-preload if ("navigationPreload" in self.registration) { await self.registration.navigationPreload.enable(); } })() ); // Tell the active service worker to take control of the page immediately. self.clients.claim(); }); self.addEventListener("fetch", (event) => { // We only want to call event.respondWith() if this is a navigation request // for an HTML page. if (event.request.mode === "navigate") { event.respondWith( (async () => { try { // First, try to use the navigation preload response if it's supported. const preloadResponse = await event.preloadResponse; if (preloadResponse) { return preloadResponse; } // Always try the network first. const networkResponse = await fetch(event.request); return networkResponse; } catch (error) { // catch is only triggered if an exception is thrown, which is likely // due to a network error. // If fetch() returns a valid HTTP response with a response code in // the 4xx or 5xx range, the catch() will NOT be called. console.log("Fetch failed; returning offline page instead.", error); const cache = await caches.open(CACHE_NAME); const cachedResponse = await cache.match(OFFLINE_URL); return cachedResponse; } })() ); } // If our if() condition is false, then this fetch handler won't intercept the // request. If there are any other fetch handlers registered, they will get a // chance to call event.respondWith(). If no fetch handlers call // event.respondWith(), the request will be handled by the browser as if there // were no service worker involvement. });