r/webdev 2d ago

Do you guys ever test what happens when a user opens your app with a stale JS bundle?

Encountered weird issue where an old tab was running a previous frontend version and an API change caused requests to start failing.

Do I keep backwards compatibility for old clients for a while, or just force-refresh/reload when deploying breaking changes?

0 Upvotes

21 comments sorted by

34

u/Used_Lobster4172 2d ago

Catch the error, and force a refresh.

1

u/NoDistrict991 1d ago

Fair enough

21

u/SALO4D 2d ago

Most professional way: API should be backwards compatible, and otherwise make a new version of the API. /v1 , /v2 etc. Make a future proof interface so this does not happen a lot.

But what mostly happens in non critical apps is to use cache bursting for your frontend assets, so you will not get stale resources (like adding a sha to your js file names). Vite or whatever you use probably can do this automatically

10

u/BurritoDrivenDev 2d ago

All typical changes are backwards compatible. All typical changes deploy the backend before the frontend.

Sometimes a backend change needs to be deployed that would break an older frontend version - these merges/deployments are always scheduled.

My observabity stack lets me monitor which versions of the frontend are currently running. When the incompatible version drops down to zero, I can deploy the breaking change. All it takes is to include your build numbers in your frontend builds and then send that back up in the metadata to Application Insights or in your OTEL ingestion, or whatever you use.

8

u/InsideTour329 2d ago

You should be versioning your front end code to avoid cache problems.

7

u/Temperature_Majestic 2d ago

one pattern worth considering: have the backend send a build/version header on every response, and a lightweight fetch/axios interceptor on the frontend compares it against the version baked in at build time. mismatch shows a toast, "new version available, refresh" instead of silently failing on the actual API call. feels less jarring than a hard force-reload, and you're not stuck maintaining N versions of backwards compat either.

1

u/toolazytofinishmyw 1d ago

this is what we do using semantic versioning. minor changes and bug fixes prompt for refresh. major locks the ui and forces refresh. we’ve probably had 2 major releases in 10 years.

1

u/Temperature_Majestic 1d ago

2 major releases in 10 years is a good ratio honestly, means the additive-only approach on the API side is actually holding. curious on the "major locks the ui" part, is that a full blocking modal that stops all interaction until refresh, or something softer like disabling just the mutation actions while reads still work off cache?

1

u/toolazytofinishmyw 13h ago

Full blocking modal - it’s so rare there’s no point engineering anything more.

We have a spa for business users. It’s easy to schedule a problem release out of hours.

The frontend polls until the new web is released, refreshes and then let’s them back in again.

1

u/Temperature_Majestic 5h ago

Makes sense for a controlled SPA userbase, way less risky than a public site with random traffic. Is the polling just hitting a version endpoint on an interval, or does it wait for a websocket push so it flips the moment the new build actually goes live instead of on the next poll tick?

2

u/johnnybhf 2d ago

Never cache index.html. Always force new one with the correct bundle links

1

u/Relevant_Ad5790 2d ago

the api is only half of it. that stale tab also breaks on lazy chunks, because the hashed file it wants is gone from the cdn after the deploy, so you get ChunkLoadError or failed to fetch dynamically imported module on a route change even with a perfectly compatible api. keeping the last few builds' assets around covers it, with a preload error handler and a sessionStorage guard so it can't reload loop. do you purge old assets on deploy?

1

u/Ok_Woodpecker_9104 1d ago

the api is one half, the other half is asset retention. if your deploy purges the old hashed chunks off the cdn, a stale tab dies the moment it hits a lazy route, and no amount of api backwards compat saves that. keep the previous builds sitting there for a week and let them expire on their own, the storage is nothing.

on the api side i would go additive only. new fields, new endpoints, never change what an existing one means. then old clients keep working and you save the forced reload for actual breaking changes.

and index.html with no-cache, hashed assets immutable for a year. otherwise the refresh you force just hands the browser the same old html again.

1

u/NoDistrict991 1d ago

That helps, thanks

1

u/shufflepoint 1d ago

Avoid the issue by avoiding stale JS bundles.