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 initand 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
optionsand arbitrary named targets (which can contain specificoptions) - Specify
grunt uglify:releaseto 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.