Reputation: 1043
I hava a react app (no CRA), using code splitting with the help of parcel-bundler.
When I click around in my app, it will fetch each of my js files once and cache them in the browser, basically injecting script tags in the header. So when I go to my users page, this will get injected in my index.html header:
<script async="" type="text/javascript" charset="utf-8" src="http://localhost:1234/Users.3ab12f6b.js"></script>
This is all fine. My problem is that when a user is browsing around and I have deployed a new version of my app on the server, the already open browser will never get these files unless it is closed and reopened on a new tab. I have tried setting <meta http-equiv="Cache-Control" content="max-age=10 no-cache">
in my index.html just to try if it does work at all, but doesn't seem to do anything.
My server is sending back Cache-Control public, max-age=0
, along with ETag and Last-Modified. Still, since the files are cached in my html document, it seems no more request is ever reaching the server for these files to check if they are expired.
I really have no more clues left. Am I missing something fundamental here?
Upvotes: 3
Views: 1032
Reputation: 3662
There are a few end points first is to periodically call an end point which returns the latest version and if there is mismatch from earlier version of the react-app then window.location.reload(true) to reload browser ignoring cache." So when I encounted this situation when deveops guys would update a file with latest commit Id and we would return this in version end point's response When there is a mismatch SPA does the the rest.
Second option would be to use service workers as it can handle it more elegantly There are multiple examples am adding the reference to them below not adding the whole example then it would make this answer TLDR
The example script I have shown below is taken from service worker file from a basic create-react-app.
function registerValidSW(swUrl, config) {
navigator.serviceWorker
.register(swUrl)
.then(registration => {
registration.onupdatefound = () => {
const installingWorker = registration.installing;
if (installingWorker == null) {
return;
}
installingWorker.onstatechange = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// At this point, the updated precached content has been fetched,
// but the previous service worker will still serve the older
// content until all client tabs are closed.
console.log(
'New content is available and will be used when all ' +
'tabs for this page are closed.
);
// Execute callback
if (config && config.onUpdate) {
config.onUpdate(registration);
}
} else {
// At this point, everything has been precached.
// It's the perfect time to display a
// "Content is cached for offline use." message.
console.log('Content is cached for offline use.');
// Execute callback
if (config && config.onSuccess) {
config.onSuccess(registration);
}
}
}
};
};
})
.catch(error => {
console.error('Error during service worker registration:', error);
});
}`
When you enter inside this check updates are ready
` `if (navigator.serviceWorker.controller) {`
this is where you have to do the logic for forcing reload
Example 1:- https://zach.codes/handling-client-side-app-updates-with-service-workers/
Upvotes: 2
Reputation: 5020
One of the alternative solution is for every web application we write some api calls to display some dynamic content in the app.
In that api calls you need to pass the build version id as one of the parameter in response.
In front end for the first time loading store the build version in localStorage or cookies. After the next call or other api call check whether the previous build version i.e from localStorage is equal to latest build version from the server api call.
If both are same, that means no need to re-fetch or refresh the page.
If the build version is different then you need to create one front end function to reload the function.
short: create one global function(ex: function checkBuild(buildVersion) to take build version from each api call response and check in it and do the page refresh.
Hope it helps.
Upvotes: 0
Reputation: 2109
I had this exact issue on my website. There are couple of good ways of solving the problem. and I can give you 2 options that I'm familiar with:
1) Once you deploy your application, send a message to your browser using sockets and have the new script url in the event payload. then you can change the local script path in the browser or reload the page to fetch the new one.
2) Create a service worker that performs an Ajax request every few minutes to test for newer version. once you found a new version, post a message to the browser with that url and do the same thing as option 1.
I hope this is what you where looking for.
Upvotes: 0