Taking Isomorphic Apps Offline With Service Workers

Written by Paul Hebert on

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.

An illustration showing two stages of offline page hydration. On the left, a mobile phone is showing a loading indicator. On the right, the loading indicator has been replaced by dummy content.

An offline page showing a loading indicator before hydrating into the requested page. The loaded page shows a notification saying, You're Offline!

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:

A phone dislaying the text, "You’re offline! This page is not available. Here are some pages you have saved for offline use: Home, About Us, Contact, Who Really Killed JFK?"

An example offline message, including a list of cached pages.

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.

Paul Hebert

Paul Hebert is a hybrid designer and developer at Cloud Four. When he's not designing and developing websites he enjoys bouldering, drawing, cooking, gardening, and eating too much cheese.

Never miss an article!

Get Weekly Digests


Leave a Comment

Please be kind, courteous and constructive. You may use simple HTML or Markdown in your comments. All fields are required.


Let’s discuss your project! Email Us