How to fix Gatsby, Ghost, and Netlify Cache Busting and Service Worker Issues

How to fix Gatsby, Ghost, and Netlify Cache Busting and Service Worker Issues

"In this post, I discuss an issue when Gatsby does not refresh and display new content upon Ghost CMS update, and how to solve such an issue."


Ever since I started making this blog, one issue stand out to me in particular. Whenever I publish a new post or edit a published one, the new changes won't be seen by someone who have visited the site previously, unless they refresh their browser twice.

At first, this seems like a caching issues, and technically speaking it is. However, most Google search point me to adding these magic lines to your static/_headers file to disable caching for these resources.

# This is recommended to prevent the caching of the service worker file itself
/sw.js   # Gatsby's default service worker file path
  Cache-Control: no-cache

/*.html
  Cache-Control: no-cache

/public/page-data/*.json
  Cache-Control: no-cache

That, however, did not resolve my issues.

My blog doesn't have much repeating visitors yet so I kind of left it as is.

As I write more and more though, I finally come down to digging deeper into the issue and found a fix!

gastby-plugin-offline

gastby-plugin-offline (docs) is a nice little plugin that allow our Gatsby site to work offline. It does that by utilizing Service Worker—specifically Workbox—that Gatsby already use by default to cache our site for offline use.

The problem is, the default runtimeCaching used by gastby-plugin-offline uses StaleWhileRevalidate handling method for our page-date.json files.

runtimeCaching: [
    {
      // Use cacheFirst since these don't need to be revalidated (same RegExp
      // and same reason as above)
      urlPattern: /(\.js$|\.css$|static\/)/,
      handler: `CacheFirst`,
    },
    {      // page-data.json files, static query results and app-data.json      // are not content hashed      urlPattern: /^https?:.*\/page-data\/.*\.json/,      handler: `StaleWhileRevalidate`,    },    {
      // Add runtime caching of various other page resources
      urlPattern: /^https?:.*\.(png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/,
      handler: `StaleWhileRevalidate`,
    },
    {
      // Google Fonts CSS (doesn't end in .css so we need to specify it)
      urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/,
      handler: `StaleWhileRevalidate`,
    },
  ],

We need to change this to NetworkFirst to tell SW to always prioritize fetching new data unless we are offline.

To override the default configuration, you can pass a workboxConfig object as an options to the plugin. Update the entry in your gatsby-config.js like this:

// gatsby-config.js

// Your gatsby config's plugins array
plugins: [
    // ... ,
    {
        resolve: `gatsby-plugin-offline`,
        options: {
            workboxConfig: {
                runtimeCaching: [
                    {
                        // Use cacheFirst since these don't need to be revalidated (same RegExp
                        // and same reason as above)
                        urlPattern: /(\.js$|\.css$|static\/)/,
                        handler: `CacheFirst`,
                    },
                    {
                        // page-data.json files, static query results and app-data.json
                        // are not content hashed
                        urlPattern: /^https?:.*\/page-data\/.*\.json/,
                        handler: `NetworkFirst`,                    },
                    {
                        // Add runtime caching of various other page resources
                        urlPattern: /^https?:.*\.(png|jpg|jpeg|webp|svg|gif|tiff|js|woff|woff2|json|css)$/,
                        handler: `StaleWhileRevalidate`,
                    },
                    {
                        // Google Fonts CSS (doesn't end in .css so we need to specify it)
                        urlPattern: /^https?:\/\/fonts\.googleapis\.com\/css/,
                        handler: `StaleWhileRevalidate`,
                    },
                ],
            },
        },
    },
        
]

Now, this will cause more bandwidth to be consumed for the users since they will always have to fetch new page-data.json for every pages, even if changes are usually rare and far between. Nevertheless, these page-data.json files are almost always very small, and other assets like images will still be cached so that shouldn't be much of a problem. NetworkFirst will also still allow our site to function when offline.

Note

The default behaviour, StaleWhileRevalidate is supposed to tell the SW to display site using what is stored in cache while it silently fetch any new changes and update its cache. Then, upon next visit, present the newly updated version while repeating the silent fetching again.

Apparently, Gatsby will also refresh itself upon any navigation in the site, if changes are present. For some reason though, these behaviour do not work for me. Thus, why I resorted to simply switching to NetworkFirst instead.

For more information about how each handling method works for service workers, Ondrej Polesny has done an amazing work explaining these in his blog post right here. You should go check that out!


Written by Romson Preechawit

Hi there! I'm a typical geek, designer, developer. Love coding, design, photography, reading, and a lot more. English is not my first language so please help correct my grammar! :)

Romson Preechawit