DEV Community

leroykayanda
leroykayanda

Posted on

Cache Busting in Ionic 3

Browsers will often cache static assets to improve performance.

Image description

This can cause issues when a new version of the application is deployed but the browser is still reading the old cached version.

With cache busting, we append a hash to the static file names e.g vendor.js becomes vendor.437b51dcc2.js. When a deployment is made the hash changes e.g vendor.437b51dcc2.js may change to vendor.74t74t5tt.js. With cache validation enforced by the meta tags below, the browser will first check if the there is a new version of the file before using the cached versions. It will thus request for the new version of the file.

<meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
Enter fullscreen mode Exit fullscreen mode

(Add these to your src/index.html as Step 1)

Step 2
Create a folder named config in the root of your project and create a file called webpack.config.js with the contents below.

var webpack = require("webpack");
const defaultWebpackConfig = require("../node_modules/@ionic/app-scripts/config/webpack.config.js");

module.exports = function () {
  defaultWebpackConfig.prod.output["chunkFilename"] =
    "[name].[chunkhash].chunk.js";
  defaultWebpackConfig.dev.output["chunkFilename"] =
    "[name].[chunkhash].chunk.js";
  return defaultWebpackConfig;
};
Enter fullscreen mode Exit fullscreen mode

This will add a hash to chunked js files. Add the code below to your package.json so that webpack is used for the hash addition.

  "config": {
    "ionic_webpack": "./config/webpack.config.js"
  }
Enter fullscreen mode Exit fullscreen mode

Run ionic build --prod. When you navigate to www/build, you will see that the chunked files now have a hash.

ll www/build  
total 3912
-rw-r--r--  1 leroy  admin   32916 May 22 18:55 0.8c4eb8d75238a2dbdd84.chunk.js
-rw-r--r--  1 leroy  admin   20629 May 22 18:55 1.576bc86e3f12e250668d.chunk.js
-rw-r--r--  1 leroy  admin   25414 May 22 18:55 10.d8e94bc91646b69468eb.chunk.js
-rw-r--r--  1 leroy  admin   21562 May 22 18:55 11.5cec3cc03fd360752259.chunk.js
Enter fullscreen mode Exit fullscreen mode

Now we need a custom script that will add hash to other static assets e.g main.js, main.css, polyfills.js etc. Create a file called cache busting in the root of your project and paste the code below.

#!/usr/bin/env node
console.log("Cache busting...");
Enter fullscreen mode Exit fullscreen mode

Ensure your CI runs chmod 755 ./cache-busting.js to give npm permission to run the cache busting script.

Add this to your package.json.

  "scripts": {
    "postbuild": "./cache-busting.js",
    "build": "npm run ionic:build --prod --release --verbose && npm run postbuild"
  }
Enter fullscreen mode Exit fullscreen mode

Run your CI to ensure the cache busting script is run and "Cache busting..." is logged.

Now we can work on cache-busting.js. Install these which are needed by the script.

npm install rev-hash@^2.0.0 --save-dev
npm install cheerio@1.0.0-rc.10 --save-dev
Enter fullscreen mode Exit fullscreen mode

Paste this code in cache-busting.js.

#!/usr/bin/env node
console.log("Cache busting...");

// This file when run (i.e: npm run postbuild) will add a hash to these files: main.js, main.css, polyfills.js, vendor.js
// and will update index.html so that the script/link tags request those files with their corresponding hashes
// Based upon source: https://gist.github.com/haydenbr/7df417a8678efc404c820c61b6ffdd24
// Don't forget to: chmod 755 scripts/cache-busting.js

var fs = require("fs"),
  path = require("path"),
  cheerio = require("cheerio"),
  revHash = require("rev-hash");

var rootDir = path.resolve(__dirname, "./");
console.log("rootDir", rootDir);
var wwwRootDir = path.resolve(rootDir, "www");
var buildDir = path.join(wwwRootDir, "build");
var indexPath = path.join(wwwRootDir, "index.html");

var cssPath = path.join(buildDir, "main.css");
var cssFileHash = revHash(fs.readFileSync(cssPath));
var cssNewFileName = `main.${cssFileHash}.css`;
var cssNewPath = path.join(buildDir, cssNewFileName);
var cssNewRelativePath = path.join("build", cssNewFileName);

var jsPath = path.join(buildDir, "main.js");
var jsFileHash = revHash(fs.readFileSync(jsPath));
var jsNewFileName = `main.${jsFileHash}.js`;
var jsNewPath = path.join(buildDir, jsNewFileName);
var jsNewRelativePath = path.join("build", jsNewFileName);

var jsPolyfillsPath = path.join(buildDir, "polyfills.js");
var jsPolyfillsFileHash = revHash(fs.readFileSync(jsPolyfillsPath));
var jsPolyfillsNewFileName = `polyfills.${jsPolyfillsFileHash}.js`;
var jsPolyfillsNewPath = path.join(buildDir, jsPolyfillsNewFileName);
var jsPolyfillsNewRelativePath = path.join("build", jsPolyfillsNewFileName);

var jsVendorPath = path.join(buildDir, "vendor.js");
var jsVendorFileHash = revHash(fs.readFileSync(jsVendorPath));
var jsVendorNewFileName = `vendor.${jsVendorFileHash}.js`;
var jsVendorNewPath = path.join(buildDir, jsVendorNewFileName);
var jsVendorNewRelativePath = path.join("build", jsVendorNewFileName);

// rename main.css to main.[hash].css
fs.renameSync(cssPath, cssNewPath);

// rename main.js to main.[hash].js
fs.renameSync(jsPath, jsNewPath);

// rename polyfills.js to polyfills.[hash].js
fs.renameSync(jsPolyfillsPath, jsPolyfillsNewPath);

// rename vendor.js to vendor.[hash].js
fs.renameSync(jsVendorPath, jsVendorNewPath);

// update index.html to load main.[hash].css
$ = cheerio.load(fs.readFileSync(indexPath, "utf-8"));

$('head link[href="build/main.css"]').attr("href", cssNewRelativePath);
$('body script[src="build/main.js"]').attr("src", jsNewRelativePath);
$('body script[src="build/polyfills.js"]').attr(
  "src",
  jsPolyfillsNewRelativePath,
);
$('body script[src="build/vendor.js"]').attr("src", jsVendorNewRelativePath);

fs.writeFileSync(indexPath, $.html());
Enter fullscreen mode Exit fullscreen mode

Build the app. The other static files should now have a hash in the name.

 ll www/build | grep main
-rw-r--r--  1 leroy  admin   10367 May 22 19:30 main.012a9a78ab.js
-rw-r--r--  1 leroy  admin  613034 May 22 19:30 main.5f460e54f6.css
Enter fullscreen mode Exit fullscreen mode

Top comments (0)