Cache Busting Angular Builds in 7 Minutes

We ran into issues with the browser cache in our Angular application a few days ago. We wish to discover solutions to this problem so that we don’t have to ask our clients to manually refresh their browsers after each deployment. In this essay, we will look at potential answers and tactics for dealing with this issue. Browser caching can occasionally cause problems with showing updated information after a deployment. In this section, we’ll look at a few common approaches to dealing with this issue.hfl-new-banner

What is the purpose of Cache Busting?

Cache-busting strategies can be used to ensure that fresh versions of your application are loaded by the browser. This is accomplished by putting a unique version number or a hash to the filenames of your assets (JavaScript, CSS, and so on). When the files change, the URL changes, and the browser downloads the updated files.

Let’s get into more detail about the cache-busting technique.

What exactly is Cache Busting?

Cache busting is a technique used to ensure that the user’s browser loads the most recent version of your web application, even if it has previously cached older versions of the files. The primary goal of cache busting is to modify the URL of the files so that the browser does not perceive them as cached resources. This is how it works:

  1. File Renaming: In this approach, you can rename your asset files (JavaScript, CSS, images, etc.) by adding a unique identifier to their filenames. This identifier can be a version number, a timestamp, or a content-based hash. For example, instead of naming your JavaScript file “app.js,” you can name it “app_v1.2.3.js” or “app_hash123456.js.”
  2. Query Parameters: Another common technique is to add query parameters to the URLs of your assets. For example, you can load your JavaScript file as “app.js?v=123456” or “app.js?version=1.2.3.” These query parameters can be set to a unique value or the application’s version number.

Certainly, here are the steps to implement the cache-busting technique for your web application.

  • Certainly, you can create a file named “versioning.build.js” in the root of your application folder, similar to where files like “package.json” and “angular.json” are typically located. The content of the “versioning.build.js” file can be structured as follows.
var fs = require('fs');
var path = require('path');
var replaceFile = require('replace-in-file');
var package = require("./package.json");
var angular = require("./angular.json");
var buildVersion = package.version;
var buildPath = '\\';
var defaultProject = angular.defaultProject;

const getDateFormat = () =>  {
    var date=new Date();
    var yyyy = date.getFullYear().toString();
    var MM = pad(date.getMonth() + 1,2);
    var dd = pad(date.getDate(), 2);
    var hh = pad(date.getHours(), 2);
    var mm = pad(date.getMinutes(), 2)
    var ss = pad(date.getSeconds(), 2)
    return yyyy + MM + dd+  hh + mm + ss;
};

const pad=(number, length) =>{
    var str = '' + number;
    while (str.length < length) {
        str = '0' + str;
    }
    return str;
}
const getNestedObject = (nestedObj, pathArr) => {
    return pathArr.reduce((obj, key) =>
        (obj && obj[key] !== 'undefined') ? obj[key] : undefined, nestedObj);
}

const relativePath = getNestedObject(angular, ['projects', defaultProject, 'architect', 'build', 'options', 'outputPath']); // to identify relative build path when angular make build
var appendUrl = '?v=' + getDateFormat();
buildPath += relativePath.replace(/[/]/g, '\\');
var indexPath = __dirname + buildPath + '\\' + 'index.html';
console.log('Angular build path:', __dirname, buildPath);
console.log('Change by buildVersion:', buildVersion, " Index Path:", indexPath);

fs.readdir(__dirname + buildPath, (err, files) => {
    files.forEach(file => {
        // console.log('------------>',file);
        if (file.indexOf("main.") > -1 || file.indexOf("custom.js") > -1 || file.indexOf("style.css") > -1
         || file.indexOf("styles.") > -1 || file.indexOf("polyfills.") > -1 || file.indexOf("runtime.") > -1) {
            const currentPath = file;
            const changePath = file + appendUrl;
            // console.log(currentPath,changePath);
              let newData = fs.readFileSync(indexPath, 'utf-8').split('\n').map(line => {
                if(line.indexOf(currentPath)>-1)
                    line=line.replace(currentPath,changePath);
                return line;
              }).join('\n');
              fs.writeFileSync(indexPath, newData);
        }
    });
});

Perform the npm install action for the following modules.

    • fs
    • path
    • replace-in-file
      ?npm install fs
      npm install path
      npm install replace-in-file
      
      ?

Remove, If commented code in angular.json or unwanted code present in the file.

  • Run the below command to build the application.
    -- Production
    ng build --configuration=production --base-href=/ && node ./versioning.build.js
    
     -- Testing
    ng build --configuration=testing --base-href=/ && node ./versioning.build.js
  • –base-href=/  -> Please check in index.html file <base href=”/”> must be same.

Without cache busting,

After running the command “ng build –configuration=production && node ./versioning.build.js”.