I have an Angular 12 application that has different build environments (dev/staging/prod) and I have configured these with output hashing on in angular.json
:
"configurations": {
"production": {
"fileReplacements": [
{
"replace": "src/environments/environment.ts",
"with": "src/environments/environment.prod.ts"
}
],
"optimization": true,
"outputHashing": "all" <-----
The output files do include a hash, but I am still seeing the old version unless I do a hard refresh in the browser.
main.07258fce7f84f8b6013e.js
polyfills.4cc5b416b55531e38cd8.js
runtime.734c276f75a5d81bc54b.js
The landing page is just a login form but the version is shown beneath the form. It shows the old version until the hard-refresh in the browser, at which point it correctly shows the new version.
Is this due to index.html
being cached along with all of it's old JS references?
If so how do I cache bust this?
In case you're using a service worker (eg @angular/pwa
which installs @angular/service-worker
along), you're entire angular app is being cached by the browser. This includes index.html
+ all javascript files + all stylesheets.
To have a new version of your application pushed to your users, you have to do 2 things:
Update your ngsw-config.json
on each new release:
{
"version": 1, // Or ascending
...
}
Call SwUpdate
:
constructor(private swUpdate: SwUpdate) {
...
//#region Check for updates
if (this.swUpdate.isEnabled) {
this.swUpdate.activated.subscribe((upd) => {
window.location.reload();
});
this.swUpdate.available.subscribe((upd) => {
this.swUpdate.activateUpdate();
}, (error) => {
console.error(error);
});
this.swUpdate.checkForUpdate().then(() => {
}).catch((error) => {
console.error('Could not check for app updates', error);
});
}
//#endregion
}
I was able to resolve this by instructing the web server cache control policy to not cache the HTML file. This is necessary because the HTML file contains the references to the Angular hashed scripts and CSS.
We are pushing out frequent updates so for now, I am setting this to to agressively not cache, but it can be adjusted to longer time periods as needed.
In our case we are using IIS, and I had to create an IIS rewrite rule in the web.config file.
<outboundRules>
<rule name="RewriteCacheControlForHTMLFiles" preCondition="FileEndsWithHtml">
<match serverVariable="RESPONSE_Cache_Control" pattern=".*" />
<action type="Rewrite" value="max-age=0" />
</rule>
<preConditions>
<preCondition name="FileEndsWithHtml">
<add input="{REQUEST_FILENAME}" pattern="\.html$" />
</preCondition>
</preConditions>
</outboundRules>