Grunt Plugin for Assets Versioning

Grunt Uglify wildcard and versioning

Seems to be there are some additional options being enabled which cause the above error.
I have corrected those and did some changes.
Run the below grunt file and see whether you can execute without any errors.

module.exports = function(grunt) {
grunt.initConfig({
clean : [ 'dest/js' ],
uglify : {
options : {
report : 'min',
mangle : true
},
my_target : {
files : [ {
src : 'src/js/*.js',
dest : 'dest/js/main.min.js'
} ]
}
},
cssmin : {
options : {
report : 'min'
},
minify : {
expand : true,
cwd : 'src/css',
src : '**/*.css',
dest : 'dest/css',
}
},
imagemin : {
dynamic : {
options : {
optimizationLevel : 7
},
files : [ {
expand : true,
cwd : 'src/assets',
src : [ '**/*.{png,jpg,gif}' ],
dest : 'dest/assets'
} ]
}
},
htmlmin : {
mini : {
options : {
removeComments : true,
collapseWhitespace : true,
collapseBooleanAttributes : true,
removeAttributeQuotes : true,
removeRedundantAttributes : true,
removeEmptyAttributes : true,
useShortDoctype : true
},
files : [ {
expand : true,
cwd : 'src',
src : '**/*.html',
dest : 'dest'
} ]
}
},
versioning : { // Task
options : { // Task options
cwd : 'public',
outputConfigDir : 'public/config'
},
dist : { // Target
options : { // Target options
},
files : [ {
assets : '<%= uglify.my_target.files %>',
key : 'global',
dest : 'dest/js',
type : 'js',
ext : '.js'
} ]
}
}
});

grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-static-versioning');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-imagemin');
grunt.loadNpmTasks('grunt-contrib-htmlmin');

grunt.registerTask('default', [ 'clean', 'uglify', 'cssmin', 'imagemin',
'htmlmin', 'versioning' ]);
}

How can I insert a version number to index.html when building with Grunt?

I ended up keeping it simple and used the grunt-text-replace plugin to replace the placeholder (@@BUST@@) with a timestamp.

replace: {
bust: {
src: ['./target/*.html'],
overwrite: true, // overwrite matched source files
replacements: [
{
from: '@@BUST@@',
to: "<%= new Date().getTime() %>"
}
]
}
}

Grunt usemin, get final path of compressed files to allow preload

The answer is no in grunt-usemin, but in one of the dependencies: grunt-filerev. This last module is the one used to create the file revisions of you css, js and other files.

After grunt-filerev is executed (executed as a subtask of grunt-usemin), it creates a summary (stored in within your grunt task, under grunt.filerev.summary). The summary contains the following information:

{
“original.js” : “destination.59bcc35a.js”
}

So you could use it later on you string replacement method/module of your choice.

You can find more information about grunt-filerev here.

Hope it helps.

Grunt module(s) to upload all static assets to S3 / CloudFront, replace paths, and invalidate old assets

Invalidating CDN assets is a Bad Idea ®. In CloudFront, it may take up to 15 minutes to complete - that would be adding 15 minutes to your deploy. Also, some browsers may hold old files because the URL is the same.

Instead, you should probably version you static assets and publish new versions under different version names.

For example:

my-app/1.2.3/main.js
my-app/1.2.4/main.js

So on, and so forth.

This gives you two advantages:

  • You can cache forever, confidently. The same URL will always serve the same file.
  • You can rollback quickly in case of a disaster deploy. Old files are where they were.

For deploying to S3, there are specific plugins for that.
I, however, prefer to simply use grunt-shell in tandem with the official Amazon AWS CLI

Configuring it would look something like this:

shell: {
cp: {
command: "aws s3 cp --recursive dist/ s3://my-bucket/my-app/"
}
}

You can use grunt to read a version variable from somewhere and automatically put all files inside the dist/{version}/ folder, while replacing any paths in your html to the correct version path.

Have Grunt generate index.html for different setups

I've come up with my own solution. Not polished yet but I think I'm going to move in that direction.

In essense, I'm using grunt.template.process() to generate my index.html from a template that analyzes current configuration and produces either a list of my original source files or links to a single file with minified code. The below example is for js files but the same approach can be extended to css and any other possible text files.

grunt.js:

/*global module:false*/
module.exports = function(grunt) {
var // js files
jsFiles = [
'src/module1.js',
'src/module2.js',
'src/module3.js',
'src/awesome.js'
];

// Import custom tasks (see index task below)
grunt.loadTasks( "build/tasks" );

// Project configuration.
grunt.initConfig({
pkg: '<json:package.json>',
meta: {
banner: '/*! <%= pkg.name %> - v<%= pkg.version %> - ' +
'<%= grunt.template.today("yyyy-mm-dd") %> */'
},

jsFiles: jsFiles,

// file name for concatenated js
concatJsFile: '<%= pkg.name %>-all.js',

// file name for concatenated & minified js
concatJsMinFile: '<%= pkg.name %>-all.min.js',

concat: {
dist: {
src: ['<banner:meta.banner>'].concat(jsFiles),
dest: 'dist/<%= concatJsFile %>'
}
},
min: {
dist: {
src: ['<banner:meta.banner>', '<config:concat.dist.dest>'],
dest: 'dist/<%= concatJsMinFile %>'
}
},
lint: {
files: ['grunt.js'].concat(jsFiles)
},
// options for index.html builder task
index: {
src: 'index.tmpl', // source template file
dest: 'index.html' // destination file (usually index.html)
}
});

// Development setup
grunt.registerTask('dev', 'Development build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', true);
grunt.config('isConcat', false);
grunt.config('isMin', false);

// run tasks
grunt.task.run('lint index');
});

// Production setup
grunt.registerTask('prod', 'Production build', function() {
// set some global flags that all tasks can access
grunt.config('isDebug', false);
grunt.config('isConcat', true);
grunt.config('isMin', true);

// run tasks
grunt.task.run('lint concat min index');
});

// Default task
grunt.registerTask('default', 'dev');
};

index.js (the index task):

module.exports = function( grunt ) {
grunt.registerTask( "index", "Generate index.html depending on configuration", function() {
var conf = grunt.config('index'),
tmpl = grunt.file.read(conf.src);

grunt.file.write(conf.dest, grunt.template.process(tmpl));

grunt.log.writeln('Generated \'' + conf.dest + '\' from \'' + conf.src + '\'');
});
}

Finally, index.tmpl, with generation logic baked in:

<doctype html>
<head>
<%
var jsFiles = grunt.config('jsFiles'),
isConcat = grunt.config('isConcat');

if(isConcat) {
print('<script type="text/javascript" src="' + grunt.config('concat.dist.dest') + '"></script>\n');
} else {
for(var i = 0, len = jsFiles.length; i < len; i++) {
print('<script type="text/javascript" src="' + jsFiles[i] + '"></script>\n');
}
}
%>
</head>
<html>
</html>

UPD. Found out that Yeoman, which is based on grunt, has a built-in usemin task that integrates with Yeoman's build system. It generates a production version of index.html from information in development version of index.html as well as other environment settings. A bit sophisticated but interesting to look at.



Related Topics



Leave a reply



Submit