I was building my portfolio and I wanted to set up an offline fallback route for when the page is loaded while offline, I've done this in Vite projects with ease using the VitePWA plugin but it would seem that Next.js has no reliable way of actually doing this.
I initially wanted to use next-pwa to set it up but next-pwa doesn't support the most recent version of Next.js which uses Turbopack by default so I went with the best practice and decided to use the serwist library to setup service workers that automatically cache the route and loads it up when offline.
The service worker set up just fine but it wasn't working the way it was supposed to, it didn't load the offline route when offline and it didn't even cache the offline route properly.
I tried multiple debugging steps but all to no avail.
Here's my sw.ts :
ts
const serwist = new Serwist({
precacheEntries: self.__SW_MANIFEST,
skipWaiting: true,
clientsClaim: true,
navigationPreload: true,
disableDevLogs: true,
precacheOptions: {
cleanupOutdatedCaches: true,
ignoreURLParametersMatching: [/.*/],
},
runtimeCaching: [
...defaultCache,
{
matcher: ({ url }) => url.pathname === "/pong.html",
handler: new CacheFirst({ cacheName: "pong-game" }),
},
],
fallbacks: {
entries: [
{
url: "/offline",
matcher({ request }) {
return request.destination === "document";
},
},
],
},
});
const urlsToCacche = ["/", "/offline"] as const;
self.addEventListener("install", (event) => {
event.waitUntil(
Promise.all(
urlsToCacche.map((entry) => {
const request = serwist.handleRequest({
request: new Request(entry),
event,
});
return request;
}),
),
);
});
serwist.addEventListeners();
Here's the service worker registration component:
export function ServiceWorkerRegister() {
useEffect(() => {
if ("serviceWorker" in navigator && process.env.NODE_ENV === "production") {
import("@serwist/window").then(({ Serwist }) => {
const wb = new Serwist("/sw.js", { scope: "/" });
wb.register();
});
}
}, []);
return null;
}
Here's the offline route page.tsx :
function Page() {
return (
You're Offline
It looks like you've lost your internet connection. Don't
worry, you can still play a game while you wait to reconnect.
Play a game?
);
}
export default Page;