React app code splitting breaks apps. Solutions?

Overview
Tools like Create React App, Vite, etc. use code splitting to improve production app performance. It’s certainly a best practice. For example, when your app is built for prod you’ll see something like this in the final build:

main.js
chunk-abc123.js
chunk-def456.js

Problem

When netlify deploys a new version of your app, files from any previous deployment are immediately deleted from the interwebs. Imagine a user had your app open and their browser hasn’t yet requested chunk-def456. Then you make a new deployment. At that moment, netlify immediately deletes chunk-def456, because it was part of the previous build.

If your user clicks on a route that needs chunk-def456, your app will break for that user. Read more: [Support Guide] Why do I see “Uncaught SyntaxError: Unexpected token <” errors? How can I use chunking or versioning for my assets at Netlify?

Also note that adding hashes to filenames (considered a best practice by many) will cause the same sort of issue.

Questions for Netlify Team

  1. You mention code splitting in that link above, but don’t mention any potential solutions. What are your suggestions? Options I can think of:
  • Turn off code splitting (really not good, lose huge performance benefits)
  • Some mechanism to force-refresh a user’s browser when new versions are deployed (also bad for many reasons - it’s unreliable, annoying to end users, and much more…imagine being halfway through filling out a form or halfway through meeting, and the app just decides to refresh)
  1. You should really add this behavior in bright bold alerts in your SPA docs. A lot of SPA frameworks and tools implement code splitting and/or file hashing by default ---- for everyone that uses those tools, using Netlify results in broken apps.

  2. I know you’re probably not going to change how your deploys behave, but as others have noted in previous threads, you would make Netlify apps a lot more robust and easier to set up if you did not immediately delete assets from previous builds. To be upfront, not having this behavior and it’s problems for end users clearly outlined in your SPA related docs makes us hesitant to continue using Netlify long-term.

Apologies if I’m missing something, but I don’t see any problem here. Netlify is behaving as it should. The file has been removed from the deploy - it doesn’t exist anymore, we serve a 404. This is how any server would and should behave. Are you expecting us to continue serving files after they’re deleted?

There are a couple of solutions:

  • Disabling hashing in your bundle - it’s not required on Netlify anyways. Vite provides an option to disable these hashed names so you can get consistent names like main.js, page-foo.js, etc. Then even if you re-deploy, the name would remain the same and the file will be served a 200 (which would also include the latest changes - which can potentially still break your app).
  • Use permalinks - Netlify’s deploys are atomic. Previous deploys are kept intact (by default for 90 days). You can link to your assets as https://<deploy-id>--<site-id>.netlify.app/asset.js and that could continue to work without issues.
  • Implement service worker caching - service workers can keep the contents cached and check the server for any updates in the background. Once you detect an update, you can show a pop-up to your users telling them that they need to refresh to get the latest changes. That’s when you delete the service worker cache, reload the page, cache the new assets again.

Again, this is not a Netlify-specific behaviour. This is how any server would work. I don’t agree with a need to document where we stick to the standard practices.

Not sure where you got it from. Assets are not deleted from the previous build. Since a particular URL can only point to a single asset at any given time, we can either show the current deploy, or the previous deploy at that URL. You did not include the old file in the current deploy, so we serve a 404. As mentioned before, you can use the permalink which would continue pointing to that asset as long as the deploy exists.

@hrishikesh wow, ok! Well:

  1. Yes, numerous other services (e.g. AWS Amplify) do retain previous build static artifacts for a period of time precisely to avoid this issue
  2. “This is how any server would work.” … Netlify’s use case (unless I’m mistaken) is to be a good way to host an application, not just a bare metal server

So, if your dev team doesn’t even think this behavior should even be documented (much less addressed in a way that would make users’ work easier) in places like “Deploy a Create React App application”, we’ll begin looking elsewhere for hosting.

The fact that it doesn’t concern your team one bit that if someone follows your docs step by step to deploy an SPA they’ll be deploying apps which break anytime a second deployment is made…that’s not a good sign.

@dataguy22 In Site deploys overview | Netlify Docs it says

No changes go live on your site’s public URL before all changes have been uploaded. Once all the changes are ready, the new version of the site immediately goes live on the CDN.

Did you read this and think the old files would still exist as well?

@dig that mentions nothing about assets from previous builds.

Correct @dataguy22, it doesn’t say “…all assets from previous deploys are no longer available…” which is obviously what you feel it should say. I get it, some people need very explicit information. What it says is the new assets (new version of the site) are immediately live therefore the old assets (old version of the site) are not available.

You are the first I have seen to raise this issue.

@dig

  1. Yes, software documentation should be very clear and explicit
  2. There are numerous previous threads asking about this issue; people have even gone out of their way to create open-source plugins to address the problem: Keep .js chunks from old deploys
  3. No need to argue about it, it’s a waste of your and my time

Whether this behavior is “right” or the “best” is obviously subjective, as are all best practices. Personally, I even probably think it is best practice to have atomic deploys in this manner – but Netlify strives (I think) to be an easy way to deploy robust, reliable applications. So either clearly document these types of gotchas, and/or build ways to allow customers to easily avoid them.

All I’m interested in at this point is determining whether Netlify thinks that the having step by step docs which, if followed to a T, lead to deploying apps that break for end-users.

@dataguy22 You’ve been bitten by the interaction of some complexity (hashed filenames + atomic deploys in this case), and like all developers you’re seeking to avoid it in future.

However the answer isn’t necessarily always for someone else to solve it upstream by injecting even more complexity.

As you yourself mention:

I think that atomic deploys are a perfectly sane decision for Netlify to have made.

Could Netlify implement some complex solution upstream so that people don’t encounter the issue?
Sure

Is it worth their investment?
Probably not

It would depend on how much of a pain point it is (or becomes) for their target market or if a competitor handles & markets the solution etc.

I think adjusting documentation is a perfectly reasonable request.
If you can point to a specific spot in the documentation that’s legitimately unclear then Netlify could clarify.

2 Likes

@nathanmartin I will again reiterate:

  1. As I clearly stated, I’m not interested in arguing, I don’t even necessarily disagree with their engineering decision
  2. All I’m interested in at this point is determining whether Netlify thinks that the having step by step docs which, if followed to a T, lead to deploying apps that break for end-users. Or do they think they should make the behavior of their application clear in the documentation and clearly state something like “if you follow these steps to deploy your application, it will break for many of your users anytime you deploy a new version” ?

I can’t answer your main question since you’re seeking an answer explicitly from Netlify and I don’t work for them, but @hrishikesh can speak on their behalf.

I do agree that documentation (where possible) shouldn’t lead you to a broken or problematic end result.

I’d imagine a note/warning would mention that many SPA producing systems create hashed filenames by default and that they can be problematic in combination with Netlify’s atomic deployments. Ideally it’d link to further explanation and outline solutions, e.g. Turning off the hashed filenames, prepending asset paths with build specific deploy urls, hosting elsewhere etc.

1 Like

@dataguy22 you can’t write a post and expect people to not engage in a healthy discussion. Opposing views is not necessarily an argument, so by calling this one, you’re essentially upsetting everyone who decided to chime in this thread.

Coming back to the point of retaining previous static build artifacts, as I have told you, previous assets are not deleted. The assets always exist at their own permalinks. There’s no one stopping you from linking to those permalinks to solve your issue.

Feel free to propose a solution. If the solution is to keep serving a 200 for assets that don’t exist in the production deployment, sorry that’s not going to happen.

As I mentioned, this is not just a Netlify issue, AWS Amplify as you mentioned also has people asking these questions:

I haven’t used AWS Amplify to know if it does what you say or not, but even if it does, at least that’s not the default or easy enough that people don’t have to ask questions. If you know how it works on AWS Amplify, please share so we can pass this feature request to our product team.

The docs are about deploying the site - which works. You have a specific use-case that happens in a specific scenario. If the docs covered every use-case and had explicit info about every issue ever faced by our users, there won’t be any new issues or questions happening as long as technologies don’t change and users continue to read the complete documentation. For a specific use-case, you need a specific solution and I have provided 3 options in my first response. You never commented on if you tried implementing those and had any issues. It seems like you’re simply here to provide feedback about your thing not working fine and not work together to find a solution. If that’s the case, I can assure you that your feedback has been registered.

Also, deploying a new version won’t break the old version. It would break only if the client was still accessing the old build when the new one goes live. There are even more solutions here than I previously listed:

  • Disable automatic publishing - This would ensure the last published deploy would remain active while you can continue adding new builds. Then when you’re sure that switching the published deploy would cause the least damage, you can manually publish the new build.
  • Use a build plugin - Build plugins can be used to store your build’s files in Netlify’s build cache. This cache can also be restored on newer builds. So you can technically add a solution in your workflow that would store your built files in the build cache, restore them selectively (based on some condition) and ensure they exist in your publish directory before deploying. This would keep the files live in the new deploy as well.
  • A non-ideal solution would be to simply employ a chunk load error handler in your application which will tell the users to refresh whenever an error occurs.

This brings me total of 6 alternative solutions and you didn’t respond to any of those (maybe you tried, but you didn’t acknowledge or share your feedback about it). If providing 6 solutions to a single problem still counts as “it doesn’t concern us”, I don’t think there’s more to say here.

Finally, about the point of documentation which seems to be your more important concern than solving the problem, like I mentioned, this is a specific use-case that’s causing issues in a specific scenario. Moreover it has potential solutions as well. In my personal opinion, based on how the documentation covers typical use-cases, this doesn’t need to be documented. We can write a Support Guide about this if it helps (at this point, it would majorly be a copy-paste of the solutions I have mentioned here) and link it from the docs. But, since this is just my personal opinion, I’d still file this for the docs team to review.

Finally, if all you were concerned about at the docs, your post’s title is indeed misleading as you seem to be asking for solutions, yet when I provided those, you continued to provide feedback about the docs.

1 Like

@hrishikesh Having seen a few people raise this recently it’d be useful to have a resource (be it documentation or a support guide) that they could be directed to.

I’d be perfectly fine with it consisting of “copy & paste” information that exists elsewhere, but something that explains why it occurs and various workarounds would be great.

If a note was added to the documentation, one of the following locations may work:
https://docs.netlify.com/configure-builds/javascript-spas/
https://docs.netlify.com/configure-builds/troubleshooting-tips/

I have already written the guide as a draft and I’m currently waiting on an internal approval to publish it live. It’s a lot more detailed than just copy paste, so I think we might go with the link from docs plan for this one after all.

The guide is now live here: [Support Guide] Handling code-splitting issues on Netlify

1 Like

Nice work @hrishikesh!

There are a few minor typos I spotted on my quick read through, but it does a great job of outlining the issue and it goes into much more detail with the various potential solutions than I was expecting.

Wowzers. Well:

  1. Most folks setting up an SPA on Netlify won’t see that guide. Your docs React on Netlify | Netlify Docs are the place this behavior should be documented

  2. I’m astounded by the way Netlify approached this. I’m here bringing up the point that if users follow your official documentation, they’ll deploy apps that break and Netlify support is here arguing with me that “well yes but only if you ever deploy your app more than one time (…really…???) and anyway you should KNOW that’s going to happen!” and “I’ve given you a bunch of solutions you haven’t even tried!”

I’m kind of astounded, and we’ll definitely be migrating away from Netlify.

Again, you came here asking for solutions (at least the title says so), but you’re complaining about docs. With that being said, seems like you ignored:

and

where I clearly mentioned:

  • This has been escalated to the docs team - but they review things weekly, so this being non-urgent will be reviewed later this week.
  • That guide would be linked to from the docs.

You have basically misunderstood most or all of what I said.

Did you try any of those 6 solutions that I spent time documenting while complaining about missing documentation? If yes, did it work? Did you run into other issues?

If you’re not here to discuss potential solutions, there’s nothing more to discuss here. If you are only concerned about docs, that point has been adressed as well. Unless you have anything productive to add to this thread, please do not respond here anymore.

To add to this, I also asked:

and

We’re acknowledging the issue and ready to work on it, but you’re going about this in circles. If you don’t like any of those 6 solutions and need a different way to handle this or have a proposed solution, we’re ready to hear that as well.

Anyone setting up an SPA that isn’t React wouldn’t see it there.

This post was the first time you pointed to the documentation you found problematic.

While I’ll preface this with “I’ve not re-read the entire thread”, I don’t think anyone has argued with you, everyone has tried to help.

If you want to host elsewhere that’s perfectly fine.
It’s even one of the options I proposed as a solution.

If you wanted legacy build artifacts to remain between builds and didn’t want to leverage any of the solutions proposed, then it’d be your only option.

Thanks everyone for the feedback and brainstorming about our docs throughout this thread. We’ve added some content in the following places to try to address these concerns

2 Likes