Bundle splitting (or code splitting) is a great way to improve load times for your large JavaScript bundle. While Webpack makes it easy to add code splitting to your app, it adds a complication to deployments.

You’re running multiple versions of your app

In a SPA, users can stay on old versions of the app indefinitely since navigation typically does not trigger the full page reload needed to download a new JS bundle. This means inter-version changes must not break currently running clients.

The implication for bundle splitting is that you must serve all historical bundle chunks so users on older app versions can lazily load the chunks specific to their version. Otherwise users on older app versions will hit errors when they try to lazily load now nonexistent app chunks.

Solutions

To ensure that users don’t stay on old versions of your app you can add an api endpoint that indicates to if the app should reload, like Slack does. You could periodically poll this endpoint and either display a message to the user to reload or automatically do so.

To ensure that users on old versions of your app can continue to navigate across chunks after a new deployment you must keep all your bundle chunks available. This means you should not clear old bundles on deployment. Cloudflare or similar caching reverse proxies should resolve the issue assuming you have long lived expirations on your static assets. (Updated 2019-07-04: A caching proxy is not enough.)

Depending on Cloudflare assumes that your users will hit all your chunks between deployments, which is not necessarily true. Instead I’ve found that using NGINX to serve local assets and fall back to an s3 bucket via try_files works well. A CDN like Cloudfront may work too, but I haven’t tried that.