Blogs from the Ranch

< Back to Our Blog

React Data Layer – Part 5: Offline Code

This post is the fifth part of an 8-part series going in-depth into how to build a robust real-world frontend app data layer. See the previous parts here:

Before we get into persisting data offline, we should talk about getting your code available to run offline. If a user has already loaded your page, it will continue to work even when they lose their internet connection. But if they are offline when they want to load up your page, or if they are on a mobile device that unloads your page in the background, they’ll get an error. In that case, no matter what data we have available offline, the user won’t be able to interact with it.

The solution to making your app’s code available offline is called a Service Worker. Service Workers are a browser feature that allow intercepting network requests and serving up responses from a more permanent cache. They give your application control over caching all assets needed to ensure the app works offline.

This sounds great, but there are some warnings! With Service Workers, it’s possible to mess up your web app in a way that’s difficult or impossible to fix unless your users manually clear out the Service Worker. Because of this, Create React App moved Service Workers from on-by-default to opt-in in version 2.0. So before you deploy a Service Worker to production you will want to understand the technology well and be confident that you’ve configured your production server correctly. Here are a few links to review:

With those warnings in mind, we’ll briefly walk through setting up Service Workers here since they are related to making your app and data available offline.

Testing Service Workers

Our app was created with Create React App 2.x, so all we need to do to enable service workers is change one line of code. Open src/index.js and make the following change:

 // If you want your app to work offline and load faster, you can change
 // unregister() to register() below. Note this comes with some pitfalls.
 // Learn more about service workers: http://bit.ly/CRA-PWA

You should now be set…at least in production. Create React App also configures your service worker not to run in development mode, to make debugging easier. This is a good choice, but to enable you to see a service worker in action, let’s temporarily enable it in development mode.

In src/serviceWorker.js, make the following change:

 export function register(config) {
-  if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
+  if ('serviceWorker' in navigator) {
     // The URL constructor is available in all browsers that support SW.
     const publicUrl = new URL(process.env.PUBLIC_URL, window.location);

We remove the check to confirm that NODE_ENV is 'production', so that the code will run in development mode too.

Now, stop and restart your webapp server to ensure this is correctly included in the build. Visit your app, and you should see the following in the console:

This web app is being served cache-first by a service worker. To learn more, visit http://bit.ly/CRA-PWA

In Chrome, switch to the Application tab, then go to Application > Service Workers. You should see an entry for service-worker.js, with the status of “activated and is running”.

service worker installed

To test that it’s working, disable the network connection on your computer and reload the page. The app should still come up again. (Note that you can’t use Chrome Developer Tools’ “Offline” checkbox for this, because you will get Chrome’s “No internet” error.)

Also note that our React Materialize styles don’t show up when we’re offline. This is because by default React Materialize recommends loading them directly from CDN servers. To get around this, we would need to download these files and serve them locally from within our app.

Rolling Back Your Changes

Now that we’ve tried out service workers, you should at least roll back the change in serviceWorker.js to disable the service worker in development. Also, in Chrome’s Application tab, click “Unregister” to remove the service worker.

unregister service worker

As far as whether to keep service workers enabled for production, as we mentioned above, consider whether you want to take the time to learn about Service Workers deeply at this point. If not, it’s safest to disable them for now.

Service Workers and API Requests

In addition to caching static assets, Service Workers can also cache dynamic HTTP responses, such as those coming from web services. In this approach, for example, the result of GET /games would be cached, and then when the app is started while offline, that cached response would be served back.

This isn’t the approach we will be taking in this guide, though. One reason is because Create React App’s service worker doesn’t support caching web service requests. But there’s a deeper reason as well. The state of your application doesn’t necessarily correspond to the last web service responses you received. Say you load the app, GET /games, and it returns one game. Then you add a new game to the list and POST it to the server. Your app’s local data now has two games, but you don’t have a cached GET /games response that includes that data.

Because of this, for web applications that involve both reads and writes, caching web service responses isn’t the best level of abstraction at which to do caching. Instead, as we mentioned in part 3, we’ll be storing the current state of the Redux store for offline access using Redux Persist. When we attempt to create new records, we’ll store those records offline as well.

How We’ll Test Offline

As we’ve seen, to get a full simulation of how your app works offline, including both offline code and data, requires enabling service workers in development mode and turning off your computer’s network connection. This will be cumbersome for our development process, because often we’ll want to disable the network connection then re-enable it.

Instead, what we’ll do is load up the app with the network enabled, then use Chrome Developer Tools’ “Offline” checkbox to simulate being offline. This will cause any web service requests we make to fail. Because we built a Reload button, we can rerun the network requests while the app is loaded to see how the app responds while offline.

What’s Next?

Now that we’ve looked into how to get our code to run offline in production, and discussed how we’ll test the offline state in development, we’re ready to move into making our data available offline. Let’s take our app to the next level!

Click here for Part 6

Not Happy with Your Current App, or Digital Product?

Submit your event

Let's Discuss Your Project

Let's Discuss Your Project