Taking Isomorphic Apps Offline With Service Workers
At 4/19/2024
For a recent project, we built an isomorphic application with Nuxt.js. It was important for our app to function for users even if they were offline, so I got to work on turning it into a PWA. But when I added a service worker, I ran into a challenge I hadn’t expected…
When I first visited the app, my browser requested an HTML file that the service worker cached. But as I navigated around, my browser didn’t request any more HTML files. Instead it only requested the API data necessary to build new pages. When I went offline, the service worker couldn’t provide the HTML for the pages I’d visited!
Is it possible for our app to build full offline pages with these fragments of cached API data?
Offline Fallback Pages to the Rescue!
One solution to this problem is to create a special offline fallback page. This should be an HTML page built the same way your app builds the rest of its pages. We’ll instruct our service worker to precache this offline fallback page, as well as the JavaScript required to run our application client-side.
Then, if you’re offline and request an HTML file that isn’t cached, the service worker can return this fallback page instead. This page has a few key responsibilities: attempting to render the requested page and displaying an offline message if that fails.
Generate Your Page Client Side
Just because the service worker doesn’t have the HTML file cached doesn’t mean your app can’t render your page!
If you’ve precached the JavaScript required to run your app, and the service worker’s cached any necessary API data, then you’ve got everything you need to build your page! To do so, you need to trigger the same page building process your app uses during client side navigation. Then your application can build out the page skeleton, and populate it with the cached API content.
You may want to display your app shell with a loading indicator until the app has a chance to build your page client-side. It’s also a good practice to add an indicator that the user is offline, and potentially let them know when the page was last cached.
Some frameworks make this easy. For example, Nuxt.js will automatically do this during app hydration. When the app hydrates, it will realize the page it’s displaying doesn’t match the current route, and render the page that does match that route.
Display an Offline Message
However, you can’t always render the page this way. Pages may rely on API data to function, and this data may not have been cached by the service worker. If that’s the case, we should at least display a fallback page to the user, explaining that they can’t access this content since they’re offline.
Even better, we can display a list of pages they do have cached. If our service worker has all of the API data required to display these other pages, we can offer those as alternatives that will work offline:
Putting It All Together
By combining isomorphic applications and service workers we can build app-like experiences that used to be impossible on the web. We just need a little help from an offline fallback page.