How to solve missing chunk code splitting errors after deploy

First of all let's understand the problem. When you enable code splitting in your bundle you are generating code chunks. These are usually split between pages the user visits. On the initial page it will only download the code for the page the user visits. Or maybe if you are using a preloader, it will download the codes required to the pages that are linked from here in the background. This is great because you don't need to put all your javascript code into one giant file, instead you can load small parts of it where you need them. Sounds great right?

The pitfall that results in the error we talk about here comes when you deploy your application. On deploy a new build is triggered that deletes the existing chunks and replaces them with new ones. As their name usually contains unique hashes each time, any reference to the old files will result in a 404 page as these files no longer exist. This is more common for deploys on services like Netlify or Heroku.

But what do you do when you encounter strange errors after deploys like Unexpected token '<' or Loading chunk failed? Let's talk about the most common solutions for this problem.

Turn off code splitting

Sounds like an easy fix that solves what causes this in the first place. But please don't do that.

Keep old versions

If you have enough control over your CDN you could keep the old chunks from the previous deploys. This way users who have older versions of your site locally won't encounter 404 errors and they would have time to migrate to the new version later when they refresh.

Double up on the CDN

You could host your code on Netlify and use a secondary CDN cache on Cloudflare. This way when your code on Netlify changes Cloudflare would still keep the old files accessible for a bit. Still this will not fix the error when the file was not accessed before, so no CF cache is available for it. Or when the CF cache expires.

Remove filename hashes

Chunks names have a different hash on each deploy. But what if you remove that? You could set up Webpack to save files with a constant name and no hash. So each time the files would accessible on the same URL, no more 404s.

Well, you probably already see the problem here. The consistency of the code would suffer greatly. The version mismatch this would create could potentially cause incompatible chunks that could result in all kinds of errors. So you probably should not do this.

Compare versions

What if you could easily determine on client side that you are a version behind and act accordingly? There are multiple solutions for this and this is one of them.

In this fix you are automatically increase a version number in each deploy on the client and on the server side. This could be done via a deploy script that checks the server version via an API and saves it on the client side after increasing it. So the next time an AJAX call is made it returns the current version number. If it is behind the client version then you can act on it.

Notify via websockets

This is more then less the same solution, but in real time. In your deploy script you could send a notification to all of your active clients if they have an active websocket connection open. Then you would know in every active client that the code has changed and act on it.

In cases like these - where you know on the client side that the code is behind - you could:
  1. Refresh the page immediately
  2. Prompt the user in a modal to refresh
  3. Queue the refresh on the next navigation call

Idle time refresh

Most of these problems occur because users don't refresh already opened webpages. So you could implement an idle time counter in the background and when the user returns after a long time just force a page refresh on them. It has the drawback that the refresh is forced even when the client code does not have a new version.

Force refresh on error

The logic behind this fix is: when you cannot prevent it then handle it. So you catch the error and force a page refresh. This way your page does not stop working and a new version is downloaded. But be careful to not run into a page reload infinite loop.

This code could look like this in the head tag of your page.

<script type="text/javascript">
  window.oиerror = function(msg, url, line, col, error) {
    if (
      msg === 'SyntaxError' &&
      error === "Unexpected token '<'" &&
      !window.location.hash
    ) {
      window.location = window.location + '#refresh'
      window.location.reload()
    }
  }
</script>

Download and cache via service worker

Download those files in the background and cache them client side, and when the 404 occurs just fallback to the local cache. This is more simple than you think.

You could achieve this for example by using the Webpack Offline Plugin. It's easy to set up and works well.

In my case for my Nuxt projects I usually use the excellent Nuxt PWA Module that uses Workbox under the hood. The initial config works like it should, but you could fine tune your implementation by adding options in your Workbox config.

By default all files under /_nuxt/* will be cached with CacheFirst strategy. This means that the site will serve these files from cache first and if they are not available they are requested over the network. You can change that if you want, just read more about Workbox strategies.

Summary

Modern problems require modern solutions. As more code moves to client side syncing those changes and keeping up-to-date versions in the browser becomes more important. I hope you could harvest some wisdom from the above mentioned solutions and found yours. Usually some combination of these does the trick.

If you have other solutions that I missed please drop me a line on Twitter, I would appreciate it.

This post was written 20 days ago.

If you liked this post tweet about it or follow me on Twitter for more content like this!