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']); }); };