File revisions

It would be awesome if we could have file revisions to avoid cache issues. I know ionic is designed for mobile platforms but cordova gives us a possibility to add browser platform which can be used for web (and we’re using it). Having static file names for assets like main.js or main.css can be problematic when its up to caching.

I’ve made a workaround with nodejs script that after browser platform build, renames the files by calculating its MD5 hash and updates the references in index.html but it would be great if it could be easier.

Webpack already gives us such possibility: https://github.com/webpack/docs/wiki/long-term-caching

But when i check it, it turned out that uglifyjs task is breaking because it looks for a file like main.[hash].js which simply does not exists.

In the time Ionic is not suporting it out of the box, i’lve wrote a small node script that calculates files MD5, renames files and replaces their refrences in other files.

Dependency is just a md5-file package to calc the hash.

//file-revision.js:

#!/usr/bin/env node
var md5File = require('md5-file'),
    fs = require('fs');

/**
 * This script renames files inside platforms/browser/www/ folder and updates their references in html files like index.html
 * The mechanism is for improve caching. So file like `main.js` will be renamed to `main.[FILE-MD5-HASH].js` and its references
 * in html files will be updated.
 */
var buildFolder = 'platforms/browser/www/';
var assetsFolder = buildFolder + 'build/';

var jsFiles = [
    'main',
    'kajam'
];
var cssFiles = [
    'main'
];
var htmlFilesToUpdate = [
    'index.html',
    'oauth.html'
];
var replacements = [];

jsFiles.forEach(function (file) {
    var hash = md5File.sync(assetsFolder + file + '.js');
    renameFile(file + '.js', file + '.' + hash + '.js');
});

cssFiles.forEach(function (file) {
    var hash = md5File.sync(assetsFolder + file + '.css');
    renameFile(file + '.css', file + '.' + hash + '.css');
});
htmlFilesToUpdate.forEach(function (htmlFile) {
    console.log('Update "' + htmlFile + '" with new file revisions.');
    console.log('Replacements: ' + JSON.stringify(replacements));
    replacements.forEach(function(replacementObject) {
        replaceInFile(buildFolder + htmlFile,replacementObject.from, replacementObject.to);
    });
});

function renameFile(input, output) {
    console.log('Rename "' + input + '" to "' + output + '"');
    fs.rename(assetsFolder + input, assetsFolder + output);
    if (fs.existsSync(assetsFolder + input + '.map')) {
        console.log('Rename "' + input + '.map" to "' + output + '.map"');
        fs.rename(assetsFolder + input + '.map', assetsFolder + output + '.map');
    }
    replacements.push({from: input, to: output})
}

function replaceInFile(file, regex, replacement) {
    var fileContents = fs.readFileSync(file, 'utf-8');
    fs.writeFileSync(file, fileContents.replace(regex, replacement), 'utf8');
}

After adding and building a browser platform, just run it:

 node file-revision.js

This should rename all files that are specified in the script and update references to them.

3 Likes

Thank you so much for this. I posted your solution (with a couple of small tweaks for files I don’t use), to stack overflow, here: https://stackoverflow.com/questions/43415537/ionic-2-change-name-of-main-js-webpack-js-output-filename-setting/43429378#43429378

It is too bad that the ionic build process interferes with the angular output hashing. It is a must, for web apps.

2 Likes

I’m currently testing your script but having problems with all the 0.js, 1.js etc. Wondering if you found a workaround