CDN caching strategy for React websites that use chunks - reactjs

What's the best caching strategy for React websites that use chunks (code splitting)?
Before using chunks I would just cache everything for one year in CloudFront, and I would delete the old files and invalidate the cache after a new version of the website was deployed. Works great.
However, after I started using chunks I started getting problems. One common issue is that after deploying a new version of the site I delete the old files and invalidate the cache. One user is already active on the old version of the site and his version of the site tries to load a chunk that no longer exists, so the site crashes for him.
One potential solution would be to keep all old files for a month or longer, and delete all files that are older than X months during the deployment process.
Is there any better solution to this problem. Am I missing something special from the service worker that CRA (Create React App) provides? If I remember correctly it provides some kind of cache busting.
Thanks.

Related

How to force-refresh browser cache automatically for each React App deployment in 2022?

By default, when a React Application is deployed, the cached version will display, even if changes were made in the new build. This requires the end user to hard-refresh their page (Ctrl+F5) to see new changes. It is not feasible to have a user do this each time.
With the constant upgrades and speed of software evolving, there are many different ways to accomplish this. However, the answers widely vary due to different practices being used each year.
What is the best practice to accomplish this in 2022? Is there a short and easy way to do this?
Edit: I am using the create-react-app project template.
This has to do with broswer caching the old pages and not React, to avoid this you need to either force refresh as you mentioned or changing your build strategy with some sort of different file naming, this can be done by using webpack caching here https://webpack.js.org/guides/caching/.
This way your scripts will have different names with each new deployment and the browser will ahve to reload the new scripts when fetching the index.html.

Cache busting a Reactjs web application

I'm developing an application in ReactJS where I quite often push new changes to the the application.
When the users load upp the application they do not always get the newest version of the application causing breaking changes and errors with the express backend I have.
From what I have researched you can invalidate the cache using "cache busting" or a similar method. Although from all the questions I have seen on stackoverflow they have no clear consensus on how to do it, and the latest update was sometime in 2017.
How would one in a modern day ReactJS application invalidate the browsers cache in an efficient and automatic way when deploying?
If it's relevant, I'm using docker and docker-compose to deploy my application
There's not one-fits-all solution. Pretty common is adding some random hash to the bundle file, which will cause browser to process the file again from server.
Something like: app.js?v=435893452 instead of app.js. Most modern bundle tools like Webpack can do all of that automatically but it's hard to give you direction without knowing your setup.

Can appengine files in asia.artifacts.../containers/images be safely deleted?

Can appengine files in google cloud store under the bucket asia.artifacts.../containers/images be safely deleted without causing any problems. There is already 160Gb of them after just a few years. The documentation doesn’t make clear what they are for, or why they are retained there:
# gsutil du -sh gs://asia.artifacts.<project>.appspot.com
158.04 GiB gs://asia.artifacts.<project>.appspot.com
I just want to know if I can delete them, or if I need to keep paying for the storage space.
Originally I thought these files might correspond to what can be seen on the "Google Cloud Platform" "Container Registry" "Images" "app-engine-tmp". But even if you delete almost everything under the container registry web interface, there are still thousands of really old files sit-in in this containers/images folder.
If I had to guess the reason for this ever growing pile of probably junk files. I suspect if versions are deleted through the web interface, the underlying files are not removed. Is that correct?
UPDATE: I did find this clue in the cloud build logs that occur when you deploy. I tested out deleting the artifacts bucket on a test project. The project still works, and builds still works. An apparently harmless error message appears in the logs. Perhaps its genuinely safe to delete this artefacts folder. However, it'd be good to have clarity on what these ancient (apparently unused) artefact bucket files are for before deleting.
2021/01/15 11:27:40 Copying from asia.gcr.io/<project>/app-engine-tmp/build-cache/ttl-7d/default/buildpack-cache:latest to asia.gcr.io/sis-au/app-engine-tmp/build-cache/ttl-7d/default/buildpack-cache:f650fd29-3e4e-4448-a388-c19b1d1b8e04
2021/01/15 11:27:42 failed to copy image: GET https://storage.googleapis.com/asia.artifacts.<project>.appspot.com/containers/images/sha256:ca16b83ba5519122d24ee7d343f1f717f8b90c3152d539800dafa05b7fcc20e9?access_token=REDACTED: unsupported status code 404; body: <?xml version='1.0' encoding='UTF-8'?><Error><Code>NoSuchKey</Code><Message>The specified key does not exist.</Message><Details>No such object: asia.artifacts.<project>.appspot.com/containers/images/sha256:ca16b83ba5519122d24ee7d343f1f717f8b90c3152d539800dafa05b7fcc20e9</Details></Error>
Unable to tag previous cache image. This is expected for new or infrequent deployments.
It should be safe to delete those. According to Google docs:
Each time you deploy a new version, a container image is created using the Cloud Build service. That container image then runs in the App Engine standard environment.
Built container images are stored in the app-engine folder in Container Registry. You can download these images to keep or run elsewhere. Once deployment is complete, App Engine no longer needs the container images. Note that they are not automatically deleted, so to avoid reaching your storage quota, you can safely delete any images you don't need.
Also as a suggestion, if you don't want to manually delete the images just in case they start piling up again, you can set up Lifecycle Management on your "artifacts" bucket and add a rule to delete old files (for example, 30 days).
This thread is similar to your concern and they have great answers. Feel fee to check it out!
IMPORTANT UPDATE: This answer only applies on Standard environment. The artifacts bucket is used as the backing storage for Flex apps images. It's used when bringing up and autoscaling VMs, so be careful when you consider deleting them.

Zero downtime deployment for angular app

I have a restful angular app that is hosted on a AWS and I'm looking for a clean and quick deployment solution to put the new site live without taking down the previous. I don't have much DevOps experience so any advice would be great. The site is full RESTFUL so its just static pages.
I was looking at setting up a dokku with AWS plugin solution but was pretty sure its overkill and may not be able to detect my app because its just static pages (no node, rails, etc).
The best way to do this is to reconfigure the web server on the fly to point to the new application.
Install the new version of the app to a new location, update the web server config files to point to the new location, and reload the server.
For inflight requests, they will be satisfied by the old application, and all the new requests will hit the new application, with no down time between them save for the trivial delay when refreshing the web server (don't restart it, just tickle it to reload it's configuration files).
Similarly, you can do this solely at the file system, by installing the new app in a new directory parallel to the old one. Then:
mv appdir appdir.bak
mv appdir.new appdir
But this is not zero downtime, but it is a very, very short down time as the two inodes are renamed. Just ensure that both the new and old directories are on the same filesystem, and the mv will be instantaneous. The advantage is that you can trivially "undo" the operation in the same way.
There IS a window where you have no app at all. For a fraction of a second there will be no appdir, and you will serve up 404's for those few microseconds. So, do it when the system is quiet. But it's trivial to instrument and do.
We ended up going with TeamCity for our build/tests and deploying via Shipit.
https://github.com/shipitjs/grunt-shipit
https://www.jetbrains.com/teamcity/
Try to use git repo for live deployment https://danbarber.me/using-git-for-deployment/
A simple solution is to use a ELB. This will enable you to deploy a new instance, deploy the code, test it, update the ELB to switch traffic to the new instance and then you can then remove the old instance.
An easy solution to this is to always be running two instances, a production and a staging. These guys should be identical and interchangeable (because they are going to switch. Assign an elastic ip to your production. When it's time to update, copy the code onto the staging, make sure it's working, and then attach the elastic ip to staging. It is now production and production is now staging. This is not an ideal solution but it is very easy and the same principals apply to better solutions.
A better solution involves an elastic load balancer. Make sure you have 2 instances attached. When it is time to update, detach an instance, perform your update, make sure it is working and reattach it. Now you will have a brief point in time where the client could get either your new website or your old website. Detach the other old note, perform the update and reattach.
The fact of the matter is even if you just overwrite files on the live server there will only be a 10ms window or so where the client could get a new version of one file (e.g. the html) and the old version of another (e.g. the css). After that it will be perfect again.

For mobile app updates why does the entire app need to be downloaded again?

I have noticed on a number of platforms: iOS, Android and BlackBerry that when updating an app the entire app is downloaded again (others mobile platforms may work this way too but I have only been exposed to these platforms).
Why does the entire app need to be downloaded again for an update instead of incremental updates?
This seems very inefficient especially if you are dealing with large apps.
Your basic question is not true for iOS, as of 6.0:
Starting with iOS 6, the app store will automatically produce an
update package for all new versions of apps submitted to the store.
This package is optimized for updating an app from one version to
another, and contains files that have changed between the prior
version of an app and the new version of the app, excluding files that
have not changed.
When used optimally, an update package is significantly smaller to
download than the full package of the app and the update will install
more quickly. Also, in many cases, this mechanism allows updates to
large apps to be downloadable over cellular networks where app
downloads are subject to a size limit.
In addition to new content, the update package contains instructions
on how to transform the prior version of the app into the new version
of the app. New files will be added, modified files will be replaced
with their updated counterpart, and deleted files will be removed as
part of this transformation. As far as the developer and user are
concerned, this process is entirely transparent and the resulting
updated app will be indistinguishable from a full download of the
corresponding updated version of their app.
So, yes, it is possible to do delta application updates, as well as delta OS updates, on mobile platforms. This capability simply has to be added by the OS vendor.
Some of the code and other content might be updated and/or changed. This requires a update. Since Android does not allow you to change/delete/add files to the installation folder, you have to download and reinstall the whole app.

Resources