Handle "Loading chunk failed" errors with Lazy-loading/Code-splitting
Asked Answered
N

2

25

We are developing a Vue.js application based on Vue CLI 3 with Vue Router and Webpack. The routes are lazy-loaded and the chunk file names contain a hash for cache busting. In general, everything is working fine.

However, there is a problem during the deployment. Steps to reproduce are the following.

  • User opens the application (let's assume route "/"), thus the main chunk file is loaded.
  • We change something in the application and deploy a new version.
    • Old chunk files are removed
    • New chunk files are being added (i.e. hashes in the chunk file names change)
  • User clicks a link to another route (e.g. "/foo")
    • An error occurs as the application tries to load a chunk file that has been renamed: Error: "Loading CSS chunk foo failed. (/assets/css/foo.abc123.css)" (this might be CSS or JavaScript)

What is the best way to avoid errors like this?

  • One approach that should work is just to retain old chunk files and delete them at a later time. That, however, complicates the deployment of new versions as you need to keep track of old versions and always also deploy the old chunk files with the new version.

  • Another (naive) approach is to just reload as soon as such an error is detected (e.g. Vue Lazy Routes & loading chunk failed). It somewhat works, but it reloads the old route, not the new one. But at least it ensure that consecutive route changes work again.

Any other ideas? Maybe there is something in webpack that could fix this?

Neisse answered 26/2, 2019 at 16:10 Comment(5)
Isnt hot reload (webpack) supposed to do exactly what you are asking?Parturifacient
@Parturifacient During development yes, but not in production.Neisse
Dynamic hash links aka chunks on production is not good idea. It should be in form of query params or anchors but not links that throw 404..Parturifacient
@Parturifacient Hashes in the file names obviously have their problems, but as far as I can tell it is the industry-standard (e.g. Google recommends it). Query parameters did not work well years ago (e.g. because of proxies) but they might work today. I cannot find a definite resource on that. But anchors most definitely won't work.Neisse
we use query versioning on production for years and it works. we generate version(f.e. ?v=1.66.5) into template on package build and include it like suffix for every local resource on page.Parturifacient
L
3

DoNOT cache the entry file(usually index.html). We add:

expires 0;
add_header Cache-Control 'no-store, no-cache, must-revalidate, proxy-revalidate';

in our nginx server config.

Then, after you refreshed the client's code, you can use the vue-router's error hook to detect the error and do something properly.

Laclos answered 24/2, 2020 at 9:43 Comment(0)
G
1

As long as you have a versioned API, you can use the old app files (just leave them on the server and delete after a vew days).

You will get problems as soon as your API changes during deployments.

I assume, you deploy a new API each time you deploy new JS code.

Then you can:

  • Pass on the API version (simply use the git hash) to the application as header with every response (JS resources, CSS, API requests, 404 responses)
  • Store the API version in your main JS entry point (or make it accessible somehow, e.g. as generated constant)
  • On each server response, check if the Server version matches your main client version.
  • If it does not: Display a prominent warning to the user (like the cookie banners) that he should reload the page (=> allows the user to save chnages in hope the API did not change for that save button).

For async components, we display normal 'not found' messages if loading fails, together with a reload button that appears instead of the component. Reloading without user interaction will cause a lot of confusion.

Gand answered 1/12, 2019 at 21:23 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.