Grunt
Grunt is development tooling to run tasks on (client-side) websites for publishing. Tasks include pre-processing (coffee, less/sass), copying files, bundling and minifying css and javacript.
NB: another popular alternative to Grunt is Gulp (npm install --global gulp
)
Bower is a package manager for client side assets (javascript, css, images). You can bower install jquery --save
and bower update jquery
.
Yeoman ("yo") is a website generator. It uses grunt and bower.
Installation
- Install Nodejs web server. This is only used for development tooling, not the target web server. (Use the installer or chocolatey)
- Install Grunt command line globally using npm
npm install -g grunt-cli
Init project
- Go to the project root folder
- Create a package.json (npm configuration; containing at least name and version, plus probably devDependencies)
Either manually ornpm init
and follow prompts
{ "name": "staticvoid", "description": "static void website", "version": "1.0.0", "devDependencies": { "grunt": "~0.4.5", "grunt-contrib-uglify": "~0.6.0", "grunt-contrib-cssmin": "^0.10.0" } }
- Create a gruntfile.js
It's a node module (module.exports = function (grunt) { /*...*/ }
There is a grunt-init plugin with various templates for new projects - You can add grunt plugins (and grunt itself) to packages.json "devDependencies"
Manually ornpm install grunt --save-dev
(note the double -) - Run grunt:
grunt
(runs the default task)
Orgrunt build
(if you have a build task)
The package.json and gruntfile.js is enough to tell npm/grunt what to do.
Gruntfile.js
The main sections
- grunt.initConfig({ /* configurations */ } );
Configure each grunt task (if not using defaults)- Each config has
options
and arbitrary named targets (which can contain specificoptions
) - Specify
grunt uglify:release
to run a specific uglify: { release: {...}} - Otherwise all targets are executed when you run
grunt uglify
- Normally there's a
files:
. You can use globbing (eg *.js, /**/*.js).- Destination: origin format.
files: { 'new.css': [ 'orig.css']}
- Arrays format:
files: [ {src: ['orig.css'], dest: ['new.css']}, ]
- Dynamic expansion format:
files: [ { expand:true,
src: ['**/*.js'],
dest: dist,
} ]
- Destination: origin format.
- Each config has
- grunt.loadNpmTasks('task');
Load the task. There is a neat task to reduce all those lines to this: require('load-grunt-tasks')(grunt); - grunt.registerTask('default', ['uglify', 'cssmin']);
Create the default task, plus others (commonly, 'build', 'test')
Most of the code is in grunt.initConfig. The naming convention is that a plugin task name matches between the sections (minus grunt- or grunt-contrib- prefixes). You can add variables at the top and refer to them as '<%= %>
- via npm (
npm install gruntTask --save-dev
) - in gruntfile.js configure it in initConfig
- loadNpmTasks
- include it in your registerTask
Minify
This is a simple gruntfile.js which just minifies javascript and css
(First do npm install grunt-contrib-uglify --save-dev
and npm install grunt-contrib-cssmin --save-dev
module.exports = function (grunt) { 'use strict'; //configure grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), //a banner stamp, using the package we just loaded banner: '/* <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n', uglify: { options: { banner: '<%= banner %>' }, dist: { files: { 'utilities.min.js': ['utilities.js'] } } }, cssmin: { css: { files: { 'style.min.css': ['style.css'] } } } }); //load tasks grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-cssmin'); //create default task grunt.registerTask('default', ['uglify', 'cssmin']); };
You can also minify html using npm install grunt-contrib-htmlmin --save-dev
module.exports = function (grunt) { 'use strict'; grunt.initConfig({ htmlmin: { target: { options: { removeComments: true, collapseWhitespace: true }, files: { 'index-min.html': 'index.html', }, } } }); grunt.loadNpmTasks('grunt-contrib-htmlmin'); grunt.registerTask('default', ['htmlmin']); };
There's also an imagemin for images, and you can use it with MozJpeg to optimize jpegs for the web (like Facebook does).
Bundling
grunt-contrib-concat concatenates files together (for bundling). Use with uglify and cssmin like this:
module.exports = function (grunt) { 'use strict'; grunt.initConfig({ concat: { js: { options: { separator: ';', sourceMap: true, }, //the !filename excludes a file (it's the destination) src: ['mu*.js', '!mu_all.js'], dest: 'mu_all.js', }, css: { src: ['style*.css', '!style_all.css'], dest: 'style_all.css', } }, uglify: { js: { files: { 'mu_all.js': ['mu_all.js'] } } }, cssmin: { css: { files: { 'style_all.css': ['style_all.css'] } } }, }); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.registerTask('default', ['concat', 'uglify', 'cssmin']); };
The problem is your html still loads the individual files. Either use grunt-string-replace or grunt-usemin to fix the individual script and link tags (html comments find the replaceable blocks).
Preview in website
grunt-contrib-connect opens a static website.
module.exports = function (grunt) { 'use strict'; grunt.initConfig({ connect: { server: { options: { port: 9001, //use this port hostname: '127.0.0.1', //localhost //base: 'www-root', //base directory open: true, //open in browser keepalive: true, //keep it alive (until ctrl/c grunt) } }, } }); grunt.loadNpmTasks('grunt-contrib-connect'); grunt.registerTask('default', ['connect']); };
Clean and copy
grunt-contrib-clean deletes files and folders, grunt-contrib-copy copies them.
Typically your root will contain an app (development) folder and dest (destination) folder. These tasks copy everything over.
module.exports = function (grunt) { 'use strict'; grunt.initConfig({ clean: { target: [ 'dist/**/*' ], //all files and subfolders in dist }, copy: { target: { options: { timestamp: true //preserve timestamp }, files: [ { expand:true, src: 'net/**', //** is files and directories dest: 'dist', //to dist/net/... } ], } } }); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.registerTask('default', ['clean', 'copy']); };
Others
grunt-contrib-watch is a filesystem watcher which launches a task (e.g. build) whenever specified files change.
grunt-angular-templates concats and minifies all the angular templates into $templateCache. Then you can concat into a single app.js.