create-react-app: Service worker fails to load new dynamic/code-split chunk
Is this a bug report?
Yes
Can you also reproduce the problem with npm 4.x?
Yes
Which terms did you search for in User Guide?
progressive web app service workers
Environment
node -v
: 8.4.0npm -v
: 5.6.0yarn --version
(if you use Yarn):npm ls react-scripts
(if you haven’t ejected): 1.0.17
Then, specify:
- Operating system: Windows 10
- Browser and version (if relevant): Chrome 63
Steps to Reproduce
- Set up a default CRA project
- Install
react-loadable
to code-split a certain React component on the page - Build, serve and navigate to the page
- Modify the component earlier (to change the generated hash)
- Build, serve and reload the page
Expected Behavior
The new version of the code-splitted component should be loaded correctly.
Actual Behavior
The installed service worker tries to fetch the old component chunk instead of the new one, resulting in a failure to load the new chunk. This is because the hash has changed since the last time the service worker was installed. Because of this react-loadable
interprets the error and refuses to display the new page, resulting in a blank page.
This is less than ideal, and the only thing I could come up is to force a reload on the homepage. This will trigger the new service worker to be installed which results in the correct component/chunk being loaded.
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Comments: 26 (8 by maintainers)
Ash @jeffposnick said, talking about service workers here is just making things more confusing. Same problem, just harder to see.
Another good solution is to “cake on the built assets”. Running
yarn run build
will wipe out any old./build/
directory but on your server, you can keep the old files from the old deployment.If the Monday build was:
build/static/js/main.aaa.js
build/static/js/chunk.111.js
…and someone loads
main.aaa.js
on that Monday but don’t click the button that causeschunk.111.js
to load yet.Tuesday’s build was:
build/static/js/main.bbb.js
build/static/js/chunk.222.js
So if that Monday user eventually tries to load
chunk.111.js
it’s going to be gone. It would be better if your server (e.g. Netlify, S3, Nginx, whatever) would be available to host all of…:build/static/js/main.aaa.js
build/static/js/chunk.111.js
build/static/js/main.bbb.js
build/static/js/chunk.222.js
that you would avoid that 404 error.
Having to reload the page just because a chunk failed feels dangerous. What if the user is in the midst of typing in their shipping address and a reloaod causes all sorts of disruption to the shopping cart checkout process.
I feel your pain. I’ve been thinking about it a lot but it’s hard to come up with a unified solution as this is mostly an issue with the hosting providers. Using something like Cloudflare to cache all your bundles on their servers (up to a month) could help if you don’t have full control over the hosting of your application.
@zackify thanks for sharing! Really helpful as this is something a lot of people run in to. Perhaps we should add a link to the post in the documentation about service workers?
If you’re using a service worker, heres some ideas @AustinGomez https://zach.codes/handling-client-side-app-updates-with-service-workers/
I am not trying to self-promote, but this was my thought process when I was setting up service workers for the first time and trying to auto update people on my apps. I think this can help
The change in https://github.com/facebook/create-react-app/pull/3924/files#diff-d2bddbd3bfb7051f9381474c844674faR446 should help avoid issues with lazy-loading for developers who use service workers via
create-react-app
.But as mentioned previously, independent of the service worker, this is a problem you need to deal with any time you’re lazy-loading versioned assets. How would you avoid it if you’re just in a scenario in which a user has a tab open for an extended period of time (without a service worker registered), and then they attempt to load a versioned asset which has been removed from the server in the interim?
Add in logic into your lazy-loading code that handles failures by, e.g., automatically performing a full-refresh, or at least showing a meaningful error to your users so that they could manually refresh, seems like it would be necessary in general.