Grunt is an amazing build tool which can be used to do a variety of things. Currently I am using Grunt tasks for concatenating and minifying css files, running the RequireJS build optimizer, preprocessing HTML (to do things like point your built HTML at compiled/minified scripts), and image minification. Grunt is also extremely useful for separating your build targets (such as development and production) and then firing up a server on your localhost. I really like the livereload grunt "watch" task which will automatically reload your server as you change source files in your editor.
My hats off to the Grunt team! I will definitely be keeping a close eye on future Yeoman generators using Grunt. This is an extremely powerful tool for all you web devs out there!
Node grunt packages installed:
{
"name": "UrbanChamp",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1",
"grunt-contrib-concat": "^0.3.0",
"grunt-contrib-uglify": "^0.4.0",
"grunt-contrib-cssmin": "^0.9.0",
"grunt-contrib-requirejs": "^0.4.3",
"grunt-contrib-clean": "^0.5.0",
"grunt-open": "^0.2.3",
"grunt-contrib-connect": "^0.7.1",
"grunt-contrib-watch": "^0.5.3",
"grunt-contrib-livereload": "^0.1.2",
"grunt-uncss": "^0.2.0",
"grunt-processhtml": "^0.3.0",
"connect-modrewrite": "^0.6.3-pre",
"grunt-contrib-imagemin": "^0.5.0"
}
}
Gruntfile.js:
'use strict';
var modRewrite = require('connect-modrewrite');
var lrSnippet = require('grunt-contrib-livereload/lib/utils').livereloadSnippet;
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
module.exports = function (grunt) {
grunt.initConfig({
clean: {
build: {
src: ['build']
},
css: {
src: ['build/App/css/*.css','!build/App/css/tidy.min.css']
},
images: {
src: ['build/App/images/*']
}
},
watch: {
livereload: {
files: [
'app/App/*.html',
'{.tmp,app}/App/css/{,*/}*.css',
'{.tmp,app}/App/js/{,*/}*.js',
'app/App/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
],
tasks: ['livereload']
}
},
connect: {
options: {
port: 8888,
// change this to '0.0.0.0' to access the server from outside
hostname: 'localhost'
},
livereload: {
options: {
middleware: function (connect) {
return [
modRewrite(
['!\\.html|\\.js|\\.svg|\\.css|\\.png|\\.jpg$ /index.html [L]']),
lrSnippet,
mountFolder(connect, '.tmp'),
mountFolder(connect, 'app')
];
}
}
},
dist: {
options: {
middleware: function (connect) {
return [
mountFolder(connect, 'build')
];
}
}
}
},
open: {
server: {
path: 'http://localhost:8888'
}
},
requirejs: {
dist: {
options: {
appDir: 'app',
baseUrl: 'App/js',
optimize: 'uglify',
preserveLicenseComments: false,
mainConfigFile: 'app/App/js/main.js',
dir: 'build'
}
}
},
concat: {
dist: {
src: ['app/App/css/*'],
dest: 'build/App/css/tidy.css'
}
},
cssmin: {
dist: {
src:'build/App/css/tidy.css',
dest: 'build/App/css/tidy.min.css'
}
},
processhtml: {
dist: {
files: {
'build/index.html': ['app/index.html']
}
}
},
imagemin:{
dynamic: {
files: [{
expand: true, // Enable dynamic expansion
cwd: 'app/App/images', // Src matches are relative to this path
src: ['**/*.{png,jpg,gif}'], // Actual patterns to match
dest: 'build/app/images' // Destination path prefix
}]
}
}
});
// load plugins
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-requirejs');
grunt.loadNpmTasks('grunt-open');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.loadNpmTasks('grunt-processhtml');
grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-imagemin');
// register at least this one task
grunt.registerTask('build', ['clean:build','requirejs', 'concat','cssmin','processhtml', 'clean:css', 'clean:images', 'imagemin']);
grunt.registerTask('default', ['build']);
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'open:server', 'connect:dist:keepalive']);
}
grunt.task.run(['open:server', 'connect:livereload:keepalive', 'watch']);
});
};