White screen of death after redeploying React-Node app

I have a fairly simple React app with a Node-Postgres backend. Whenever I rebuild and deploy a new version to fly.io, the page loads with a white screen. Hard refreshing fixes it, but I would prefer that it work normally, because visitors will not know to do a hard refresh.

I’ve tried looking at the failing page with developer tools, and I get the following error:

2.b8c23267.chunk.js:1 Uncaught SyntaxError: Unexpected token '<'

Probably just my ignorance, but this message tells me nothing other than that there is some error loading the javascript. I can’t seem to dive in any deeper to figure out what is causing it. Because it’s trying and failing to load the javascript, putting a message to the user in <noscript> doesn’t do anything.

I’ve also searched online and tried multiple fixes, but none works for my problem.

Hi,

My guess what’s happening would be that the “unexpected token” error is because each time you deploy, your app JS will change, and so its files will have a new hash in their name (which is correct, as their content has changed and that acts as a cache-bust). Hence a request for old-hash.chunk.js is probably returning a 404 (or equivalent) error as it no longer exists. That 404 may be a HTML file. Which would start with <. Which confuses the app.

This is a known, common issue with SPAs generally. How do you get/force the user to reload the page (which remains called index.html).

One idea is to return a header (SPA version) in the API’s response headers. The SPA checks that against the value it holds (ee.g in local storage). If it doesn’t match, it knows it has been updated so pops up a dialog/toast to ask the user to reload the page. To get the latest index.html, to get the latest hash.js. Not ideal though.

Here are some more thoughts about this:

Thank you for this. Having a better understanding of the cause has already helped me to make some progress. Haven’t solved it completely yet, but I’ll post an update once I have with some more info on what I did.

1 Like

No problem.

Another solution (kind of) would be to persist the old version’s static assets. Perhaps from a volume. Or an external store, like S3 (or equivalent - there are lots of cheap ones out there).

Existing users that haven’t refreshed the page will still get all the assets their index.html expects (like old-hash.chunk.js). No 404, so no < error.

New users (or people who have refreshed the page since the deploy) will get the new index.html and so get the new-hash.chunk.js. Works too.

The downside of this approach is if you were to make any breaking change between versions (e.g add a new API endpoint, change response or whatever). The old .js files would load, but what they do with the data then wouldn’t.

Yep, it would be interesting to know how you solve it since there isn’t a perfect solution.

Haven’t yet actually fixed it, but I did come up with a way of dealing with it temporarily that is delightfully kludgy. Basically I create a static error message in the index.html file and then have React overwrite it with an empty div. If the site doesn’t load properly, the error message remains visible. If it does, the error message gets overwritten and the site loads in its place. Perhaps others can take advantage of this hacky solution if they need to do something quickly like I did.

Here’s my code:

index.html:

<div id="loadError">
  <p>Error loading site. Please perform a <a>hard refresh</a> to reload (cmd + alt R, cmd shift R, etc...)</p>
  <p>We are working to correct this error so that it does not occur in the future. This message is (hopefully) a temporary solution until we find a permanent one.</p>
</div>

and index.js:

const loadError = ReactDOM.createRoot(document.getElementById('loadError'))
loadError.render(<></>);
1 Like