I have a SPA Angular website. Whenever we release a change to the website, the user's browser does not go back to the server to get the new javascript files. The app happily keeps running in the user's browser, and while it will make ajax calls for data, the javascript files do not change. This can cause errors if the signature of the back-end API being called changes, etc. If the user refreshes the page, they get the updated javascript files and everything works fine after that.
Is there a way to tell the browser that the site has been updated and to get the new javascript files, rather than just running the app with the same files?
I use the Angular CLI to build the application, so when the website is released, the javascript files have hashes at the end etc. This isn't an issue with files being cached and not updated... it's an issue with the browser knowing that it needs to request the files or refresh the page.
You could use web workers to poll the server for changes and refresh the browser when changes are found.
An alternative to web workers is using setInteterval just refresh after a given time.
Yet another alternative is to have a version number in your API responses, and the JavaScript handlers would refresh the page when the version numbers are out of sync.
You could write a program in your angular code that:
periodically checks the version of the api if changes where made
does the periodic check to ascertain when the user is idle AND when the user is not in a edit page with dirty fields.
refreshes the page when step 2 condition is met
use this library to watch idleness
https://github.com/shawnmclean/Idle.js
If the file udated have the seame name add this text after the "?" like "?ver1.1" is suppose to tell the browser that there is a new version of the file.
you can use manifest file
https://html.spec.whatwg.org/multipage/offline.html#manifests
another way is with
CacheStorage,clear()
Related
I'm about to release a web application with a few pages. Each page is a Vue.js bundle. So on each page, there is a single javascript bundle & a single CSS file included, and a single div with a unique ID in the page where the app elements get mounted.
I need to be able to make updates to the static CSS/JS files without major service disruption. I'm using a Google Firebase backend for the application data, so if the client code doesn't update when an update is deployed, it could try to write to the database in the wrong format in an incorrect way. So, caching of the script files has been a problem.
I was initially under the impression that caches are invalidated when the hash of the file contents changes, but apparently that is not true. So, the core question is: How can I invalidate the browser cache of these files every time the content is updated?
What makes things complicated is that the web application may be embedded on clients' websites, by adding a small snippet to the page. And, I don't want to modify these snippets for every update - so I can't to change the filename with each version. E.g. in someoneswebsite.com.au/app/index.html:
<div id="my-app-mount"></div>
<script src="https://mywebapp.com.au/app/homepage.js"></script>
What won't work for me
Adding a query string or changing the filename with every update (Or other server-side tricks in PHP): I can't use any preprocessor as the snippet needs to be embeddable on other sites in HTML only.
Just setting a short TTL in the cache for these items. I need updates to work overnight, so I'd have to go down to just an hour or two. And this leads into the next point;
Disabling caching completely for these items: I don't want to flog my server with the extra traffic.
Just telling my users to do a hard-reload if they have any issues - this is a client-facing product.
My ideas for a solution so far
Change the filename with each upgrade app-1.0.js, app-1.1.js and so on, and add a 'bootstrap' script that gets the latest version based on a version string read from Firebase. However, this adds extra latency to every single page load as we need to hear from the database before loading the main JS payload.
In each javascript bundle, add a check to compare the app version with a version number retrieved from Firebase. If the script is out of date, we can programatically invalidate the cache and refresh the page (but how to do this?)
Some combination of HTTP cache headers, to always invalidate the cached copy if the hashed contents don't match the server.
I've made a javascript file change on my Azure app service web app. I can see the change via FTP download and via App Service Editor. However, when I log into the application, the desired change in behavior of the code, which should be very obvious, has not changed.
If I F12 (in Chrome) and look at the Source, the change has not been made.
I did a "hard reload" of cache from within DevTools (F12). Still no change.
Is there something else I need to do to implement this change in the application, i.e. stop and restart the application?
UPDATE:
Light bulb goes on: the JS is running from mini-fied bundles, so changing one separate JS file won't make a difference. Would be nice to know about whether the app WOULD have accepted a change without restart, however, not critical for solving my problem.
You can append a version parameter to avoid client-side caching. Try adding a caching buster to the URL for requesting the JS file. For example. "/app.js/?v=v1". The value of the version can be changed every time you deploy new changes.
On cloudflare I want to disable caching and see my website changes immediately that I've pushed live.
Things I've tried:
I've put development mode on.
Create a bypass on caching in page rules.
Purged an individual webpage.
Purged the website.
Set cache to clear every 2 hours.
None of the above worked.
Tech I'm using:
Angular2
SystemJS
Typescript which becomes javascript on build.
Firebase for hosting and database.
Cloudflare for SSL etc.
The only way people see my website changes, it if they hard refresh.
The main problem is I've got a javascript file called app.js and its has all my javascript in for my Angular app. And it doesnt seem like its trying to get the resource in the browser.
I've changed the app.js to app.js?1490959855777
And still doesnt fetch the file again.
I basically want to see my JS file without a user having to hard refresh.
Based on the discussion above, it looks like the caching is happening on the browser - since a hard refresh will get the new file contents.
I think what happened is CF told the browser to hold onto that file for a very log time. And the browser is listening to that request.
Because you can't ask your users to do a hard refresh, you'll need to rename the static files that are being cached so aggressively.
I realize a similar Q was asked 5 years ago. I'm hoping there may be a better answer today.
Is there a programmatic way to tell a browser to expire its cached version of this page & to request a refresh from the server, next time? Time based expiry is not fast enough.
Requirement:
I want the client to constantly reload the the page from its own cache, until I tell it (via SignalR) that the page is obsolete. Then if I could flush just-that-page from the local cache, the next time the user looked at it, it would pull the latest version from the server. So once more it would be cached locally.
Why?
The data on the page takes a long time to download & the javascript adds seconds to the render time. Often it remains static for 30 mins or more. But occasionally it changes a few times a minute. So a fixed time interval cache, doesn't work.
ASP MVC lets me invalidate the Output cache of a page on the server. Which is great. If I could do the same on the client it would be an awesome speed improvement.
Note: I'm not changing the CSS, Images or Javascript. I just want strip out a lot of JScript & to do most of the HTML rendering on the server, once per data change event.
I had similar situation in my project where we wanted all clients to take latest version of files after each release. It was a simple spring MVC application. The fix we applied was we created a jsp tag which would add release number to all URL sent to server like:
www.abc.com/test.html/1
www.abc.com/test.html/2
Each time there is change in URL like this the browser does not uses cached copy but gets file from the server.
Release number you can keep in a config file and change after each release.
I version all of my client side JS files like "/js/myfile.js?v=3903948" so that my clients don't need to clear their browser cache to ensure they get the updated files. But every time I push an update, without fail, at least one person runs into a problem where they are running the old version and get some kind of error. I used to think that this was just them having already been on the page during the release and just needing to reload the browser, but this happened to me today when I was definitely not previously on the page. I browsed to the live site and was running the old code. I needed to do a browser refresh on that page to get the new file.
What can cause this?
PS I was using Chrome on Win7, but I have seen clients report this before on all different browsers.
If your main web page can also be cached, then the old version of that page can be requesting the old version of the JS file. JS file versioning works best if the page that actually refers to the JS file cannot be cached or has very short caching time.
I agree with jfriend00 about the webpage itself being cashed and thus requesting the old javascript version.
To prevent this, you can have the javascript file loaded by an ajax (Post) request, either requesting the server what is the accurate(latest) version number to download, or requesting the javascript itself and inserting it, e.g. in the head of the page.
Edit: see for example here
I make a quick AJAX request to the server for the version it expects them to have, then force them to refresh the page if the client's script is old.
Seems that proxy or some load balancer is serving old content instead of new. Also check IIS/webserver settings how are these files cached/expired.
You can check what is going on on the wire with tools like Fiddler.