Sails.js Asset Versioning

If you are using Sails.js for your applications, you often get into asset versioning problem. Which means, you update your Sails.js application but due to the cache settings, your users still load old Javascript and css files. Which means there are possibilities for your website to break. This could potentially lose you a user (or a customer). One way to get this to work is to tell users to clear their cache thus allowing new assets to load. Clearly this isn't practical as from a user's perspective, it is actually faster to search for another website. So they will just click away.

We solved our Sails assets versioning using the following steps.

1. First of all download the node module called grunt-rename (https://www.npmjs.com/package/grunt-rena…). To do this go to your project directory in the command line and enter npm install grunt-rename --save-dev

2. Create a new file under the folder /tasks/config and name it rename. js. Content of this file should look like the following:

module.exports = function(grunt) {
    var versionDate = new Date();
    var timestamp = versionDate.getTime();
	grunt.config.set('rename', {
		js: {
				src: '.tmp/public/min/production.min.js',
            	dest: '.tmp/public/min/production.v'+timestamp+'.min.js'
			},
		css: {
				src: '.tmp/public/min/production.min.css',
            	dest: '.tmp/public/min/production.v'+timestamp+'.min.css'
			}
	});
	grunt.loadNpmTasks('grunt-rename');
};


What we are doing here is renaming our assets based on timestamp. This makes every revision unique and thus the users will always download new assets on application update (every sails lift).

3. In the same folder (/tasks/config) there should be another file named Sails-linker.js. Open this file and make the following changes:

For objects prodJs, prodJsRelative, prodStyles and prodStylesRelative replace the string production with **. For example you may have the following setting right now:

prodStyles: {
			options: {
				startTag: '<!--STYLES-->',
				endTag: '<!--STYLES END-->',
				fileTmpl: '<link rel="stylesheet" href="%s">',
				appRoot: '.tmp/public'
			},
			files: {
				'.tmp/public/index.html': ['.tmp/public/min/production.min.css'],
				'views/**/*.html': ['.tmp/public/min/production.min.css'],
				'views/**/*.ejs': ['.tmp/public/min/production.min.css']
			}
		},


Change this to

prodStyles: {
			options: {
				startTag: '<!--STYLES-->',
				endTag: '<!--STYLES END-->',
				fileTmpl: '<link rel="stylesheet" href="%s">',
				appRoot: '.tmp/public'
			},
			files: {
				'.tmp/public/index.html': ['.tmp/public/min/**.min.css'],
				'views/**/*.html': ['.tmp/public/min/**.min.css'],
				'views/**/*.ejs': ['.tmp/public/min/**.min.css']
			}
		},


4. Now the final step. Open /tasks/register/prod.js and add 'rename' before linker calls. You may have something like the following:

module.exports = function (grunt) {
	grunt.registerTask('prod', [
		'compileAssets',
		'concat',
		'uglify',
		'cssmin',
		'sails-linker:prodJs',
		'sails-linker:prodStyles',
		'sails-linker:devTpl',
		'sails-linker:prodJsJade',
		'sails-linker:prodStylesJade',
		'sails-linker:devTplJade'
	]);
};


Change this to:

module.exports = function (grunt) {
	grunt.registerTask('prod', [
		'compileAssets',
		'concat',
		'uglify',
		'cssmin',
		'rename',
		'sails-linker:prodJs',
		'sails-linker:prodStyles',
		'sails-linker:devTpl',
		'sails-linker:prodJsJade',
		'sails-linker:prodStylesJade',
		'sails-linker:devTplJade'
	]);
};


That's all. Now every time you run your app in the production mode (not development mode), you will have your assets based on the server start timestamp. For example your style tag will look like the following,

<link rel="stylesheet" href="/min/production.v1422333108891.min.css">


and your script tag will look like the following,

<script src="/min/production.v1422333108891.min.js"></script>