Invalidating an HTML5 cache (manifest) completely? - iphone

I have an iPhone web-app, and I want to know how to force a cache refresh.
My cache manifest is this:
CACHE MANIFEST
index.html
file1.css
file1.js
index.html is the meat of the application, so I put that in the cache. At this point, I seem to be boned, as I can't figure out how to get iPhone to invalidate the cache. Even going to Settings > Safari > Clear Cache doesn't work, although I'd like to be able to control this programatically. Removing index.html from the manifest and re-adding it seems to work, but I would have to know that all my clients had a clean hit of the updated manifest.
How do I cache index.html and still have it updated when it changes?

Off the top of my head, any change to the manifest will do the trick - and manifests can contain comments starting with #. Just add a random comment and it'll work.
It's a useful property, when I worked on an HTML5 application in a git repository I used to have the manifest automatically regenerated with a comment containing the HEAD hash after each commit so that the changes always propagate to the users.

There seems to be a bug in WebKit Browsers preventing them to reload the website on manifest changes, see this link
Have no clue for a workaround except when I call the index.html directly.
No chance for a iPad/iPhone-WebApp pinned to do the job...

Yes, you can use JavaScript to force Safari to reload cached resource files.
According to Apple, modifying the cache manifest file will cause Safari to reload any changed resource files. But those reloaded files won't be used by the browser until the user visits the site a second time. That delay can a pain, especially during development.
To force Safari to reload the cache contents immediately, Apple says you can use this JavaScript to manipulate the applicationCache object:
function updateSite(event) {
window.applicationCache.swapCache();
}
window.applicationCache.addEventListener('updateready', updateSite, false);

Related

Never revalidate cached assets PWA service worker WorkBox

So I'm having an issue and I think I know what's happening but I'm not sure.
I have a PWA being deployed in versions. Each version obviously some files change. My bundler hashes the files into files (eg, /assets/OnboardingIntro.89e181b7.css).
What was happening was that when there would be a new deployment pushed along with a new manifest/SW, sometimes, there would just be a blank screen. A refresh fixes the issue.
In the network tab, it would say something like 'text/html' is not a valid JavaScript MIME type.
I figured this was happening because new PWA assets would be pushed with different hashes (for good reason), and the old ones would be deleted (also desirable). And what was happening was that on this current load, the old SW was requesting revalidation of its files. Even the SW worker was being told to cache these files, perhaps there was some logic that was re-checking them. And because rewrites go to index.html, these JS files were then being recognised as HTML causing errors.
Upon further inspection I found this header in the JS file:
cache-control: public, max-age=0, must-revalidate
Which suggests that the reason this is happening could be because the browser is being told to revalidate the SW's cached files every time.
But I would like really understand the logic behind re-validating cached assets in service workers. Can I guarantee that an installed service worker would never update a cached file until a new SW/manifest has been initiated? Because that's the only I can see this issue being solved. Otherwise every time I make a new deployment there's a window in which an old service worker might ask for an old file that no longer exists.
What is the logic behind revalidating? Does the SW use the cache headers? Is it just a matter of setting the cache header to an insanely long time? Is there another setting in the service worker, or in WorkBox to do this?
Another question would be, if an old asset and new asset's filenames matched, and these cache headers were set to infinity, would the new SW force a single revalidation to grab the new file? Or would it fallback to the old one if it's cached in the browser?
Thanks!

Keycloak CSS is not updating in browser

I am upgrading Keycloak from 9.x to 12.x in a development environment. I initially copied some custom themes forward, and found that the styling was badly broken (no surprise). I reviewed my FTL files, copied some of the core changes into my theme, and things are much better - just some minor issues to adjust.
Now the problem. I've made the changes to my login.css file, but those changes aren't showing up in the browser. It continues to fetch an old version of my custom CSS file.
What I have tried (multiple times for most of these):
Clear browser cache
Restart Keycloak
Check ownership/permissions of theme files
Restart entire server
Load CSS file directly
Load CSS file directly with meaningless parameter added (trying to bypass any possible middleman caching)
Confirm new version of Keycloak is the one running
Load page in other browsers
I've also now grepped the entire Keycloak directory for some of the CSS rules I've removed, and I can't find any copies of the "old" css file anywhere that might be getting referenced by accident.
Also, there are no messages in the Keycloak log when loading the CSS file.
I want to figure out how to get Keycloak to deliver the updated CSS to the browser.
Blind guess, so please don't blame me if it doesn't work. (question should include minimal reproducible example):
Edit /opt/jboss/keycloak/standalone/configuration/standalone-ha.xml and update it as follows:
<theme>
<staticMaxAge>-1</staticMaxAge>
<cacheThemes>false</cacheThemes>
<cacheTemplates>false</cacheTemplates>
...
</theme>
For me it worked when changed this file
standalone.xml
like below way
<cacheThemes>false</cacheThemes>
<cacheTemplates>false</cacheTemplates>
I think it is because I am using single instance mode instead cluster ha mode.
Apart from disabling cache, as described above, you can also adjust the theme resource URLs, breaking the client-side cache. It's a bit of a hack, but you can directly modify the resource tag portion of the URL by adjusting the database migration_model.id value.
references:
https://github.com/keycloak/keycloak/blob/main/model/jpa/src/main/java/org/keycloak/models/jpa/MigrationModelAdapter.java
https://medium.com/#hokumski/how-to-drop-keycloak-theme-cache-without-clearing-browser-data-aebb499ae83b
You must delete the path keycloak-server\standalone\tmp\kc-gzip-cache\sbgwq or otherelse folder... and test in a browser in incognit mode.

Problem with HTML5 offline in mobile web app

I can't get offline mode in iphone mobile Safari to work.
I have included my cache manifest file in the root of my directory.
<html lang="se" manifest="cache.manifest">
My cache.manifest looks like
CACHE MANIFEST
CACHE:
/images/background-iphonelines.png
/images/acne.jpg
/images/lisa.jpg
/images/bruno.jpg
/images/urban.jpg
/shops/acne.html
/shops/lisa.html
/shops/bruno.html
/shops/urban.html
/shops/shops.css
/style.css
script.js
guide.html
NETWORK:
*
I also included a .htaccess file in my root directory with the content
AddType text/cache-manifest .manifest
When I'm trying to open my app on my Iphone it still says "Can't open page" (or similar, have my page in swedish).
Does someone have any suggestions what I'm doing wrong?
Your mark-up and cache file look fine, but if the site won't go off-line there's a problem with the cache. It only has to fail on one element, and the whole thing won't work. Have you tried debugging your cache file? This post will help:
Jonathan Stark, Debugging HTML 5 Offline Application Cache
Note this won't tell you which asset causes the failure (if any), but it will tell you if your cache is working or not.
I actually had a similar issue yesterday. Try removing the CACHE: and just listing the items for the cache. I found this by accident and it seems to now work on IOS for me. Also, I added a comment field at the top to make sure I can invalidate the cache. I would give that a try.
I also had the same problem. I included the lines below in the cache.manifest file & it fixed for me.
NETWORK:
*
I was struggling for 2 hours with this and finally I've managed it! HORAY! I've added "/" to cache, this was the problem...

GWT Caching Concept

Can someone explain to me in simple term the concept of caching in GWT. I have read this in many places but may be due to my limited knowledge, i'm not being able to understand it.
Such as nocache.js, cache.js
or other things such as making the client cache files forever or how to make files cached by the client and then if file get changed on the server only then the client download these files again
Generally, there are 3 type of files -
Cache Forever
Cache for some time
Never Cache
Some files can never be cached, and will always fall in the "never cache" bucket. But the biggest performance wins comes from systematically converting files in the second bucket to files that can be cached forever. GWT makes it easy to do this in various ways.
The <md5>.cache.js files are safe to cache forever. If they ever change, GWT will rename the file, and so the browser will be forced to download it again.
The .nocache.js file should never be cached. This file is modified even if you change a single line of code and recompile. The nocache.js contains the links of the <md5>.cache.js, and therefore it is important that the browser always has the latest version of this file.
The third bucket contains images, css and any other static resources that are part of your application. CSS files are always changing, so you cannot tell the browser 'cache forever'. But if you use ClientBundle / CssResource, GWT will manage the file for you. Every time you change the CSS, GWT will rename the file, and therefore the browser will be forced to download it again. This lets you set strong cache headers to get the best performance.
In summary -
For anything that matches .cache., set a far-in-the-future expires header, effectively telling the browser to cache it forever.
For anything that matches .nocache., set cache headers that force the browser to re-validate the resource with the server.
For everything else, you should set a short expires header depending on how often you change resources.
Try to use ClientBundle / CssResource; this automatically renames your resources to *.cache bucket
This blog post has a good overview of the GWT bootstrapping process (and many other parts of the GWT system, incidentally), which has a lot to do with what gets cached and why.
Basically, the generated nocache.js file is a relatively small bit of JS whose sole purpose is to decide which generated permutation should be downloded.
Each individual permutation consists of the implementation of your app specific to the browser, language, etc., of the user. This is a lot more code than the simple bootstrapping code, and thus needs to be cached for your app to respond quickly. These are the cache.html files that get generated by the GWT compiler.
When you recompile and deploy your app, your users will download the nocache.js file as normal, but this will tell their browsers to download a new cache.html file with the app's new features. This will now be cached as well for the next time they load your app.

iPhone application cache and XMLHttpRequest

I have a WebApp that I've been try to make work offline. The WebApp is too big, even minified, to simply use the application cache (things download but I eventually get a window.applicationCache error). I'm trying to use XMLHttpRequest to get the larger scripts and main html and keep them in localStorage and just keep a small loader script in the application cache. The problem I'm seeing is that the XMLHttpRequest returns a network error when the loader script is being served locally. When the the cache is downloading no error is returned and it works fine. When I turn off the application cache the loader works fine, but of course then I need the network to get the loader.
I tried setRequestHeader("Cache-Control", "no-cache") but that didn't help.
Anybody have a clue?
What does your network: section in your manifest look like?
I found that if I weren't allowing wildcard network traffic it wouldn't load with XMLHttpRequest. So changing it to:
Network:
*
did the trick for us.
I think I found a solution. It would probably work for others.
I split the loader into two separate HTML files: one that uses XMLHttpRequest to get all the required files and put them in localStorage (the loader) and another that simply reads the files from localStorage and writes them into the document (the booter) with appropriate wrappers (e.g. ). The booter has a manifest file to keep it in the application cache. The loader does not. The user first invokes the booter. If the booter finds files already in localStorage it does it's thing. Otherwise, it uses location.replace() to invoke the loader. The loader loads the files from the server using XMLHttpRequest and puts them in localStorage, and then re-invokes the booter using location.replace(). This seems to not cause an network error.
In order to run offline, the user must invoke the booter in the iPhone Safari browser (which invokes the loader, which re-ivokes the booter) which boots the WebApp. In Safari, the user must then add the WebApp (the booter link) to their Home Screen (using the "+" button at the bottom). When offline the user can get to the app from the Home Screen icon. It takes a few seconds to re-render, but it's fully functional after that. It's the same delay when online. Invoking the link from the iPhone Safari browser will not work offline, though it will work online.
The booter monitors the application cache's "updateready" event so that when online and the when iPhone detects a change in the booter's manifest file and downloads a new booter, it will swap the new cache (window.applicationCache.swapCache()) and invoke the loader using location.replace() again. I also add an alert() to let the user know something funky is going on. So changing the manifest file (I mean making some bytes different, not just tweaking the modify time) will cause clients to get new files when online.
Interestingly, I noticed that localStorage set up in Safari is not available to the same page served from invoking the Home Screen icon, even though the cookies transfer! So the first time the booter is invoked from the icon it will reload the files even though they were previously loaded in Safari. Also, I had to explicitly prevent the loader from being cached as it was not reloading from the server when the rest of the files were updated.
You are correct. Ultimately it was the network section in the manifest.
I thought the site where the application was loaded from was included automatically and you didn't need to mess with it, but it's not true. You need to put the site in the network section.