# Install grunt-cli GLOBALLY
$ npm install -g grunt-cli
It uses the locally installed grunt via require
# Install command line completion
$ eval "$(grunt --completion=bash)"
Put this in ~/.bashrc
or elsewhere
Two files:
package.json
Gruntfile.js
or Gruntfile.coffee
package.json
{
"name": "my-project-name",
"version": "0.1.0",
"devDependencies": {
"grunt": "~0.4.1", /* required by grunt-cli */
"grunt-contrib-jshint": "~0.1.1" /* a grunt plugin */
}
}
npm
tips# Add to devDependencies section
$ npm install grunt-contrib-uglify --save-dev
# Add to dependencies section
$ npm install restify --save
# Create a new project (package.json)
$ npm init
Gruntfile.js
Four parts:
Gruntfile.coffee
module.exports = (grunt) ->
grunt.initConfig(
pkg: grunt.file.readJSON('package.json'),
uglify:
options:
banner: '/*! <%= pkg.name %>; */\n'
build:
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
grunt.loadNpmTasks('grunt-contrib-uglify')
grunt.registerTask('default', ['uglify'])
module.exports = function(grunt) {
// Do grunt-related things in here
};
// Project configuration.
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
options: {
banner: '//<%= grunt.template.today("yyyy-mm-dd") %>'
},
build: {
src: 'src/<%= pkg.name %>.js',
dest: 'build/<%= pkg.name %>.min.js'
} } });
// Load the plugin that provides the "uglify" task.
grunt.loadNpmTasks('grunt-contrib-uglify');
// Load all tasks defined in local tasks directory
grunt.loadTasks('tasks');
(matchdep)
# Load a bunch of plugins
grunt.loadNpmTasks('grunt-contrib-watch')
grunt.loadNpmTasks('grunt-contrib-csslint')
grunt.loadNpmTasks('grunt-contrib-cssmin')
grunt.loadNpmTasks('grunt-contrib-coffee')
...
grunt.loadNpmTasks('grunt-mocha')
# Load tasks from package.json matching "grunt-*"
require('matchdep')
.filterDev('grunt-*').forEach(grunt.loadNpmTasks)
// Default task, $ grunt
grunt.registerTask('default', ['uglify']);
// Deploy task, $ grunt deploy
grunt.registerTask('deploy', ['concat', 'uglify', 'scp']);
grunt.initConfig({
// Arbitrary non-task-specific properties.
my_property: 'whatever',
my_src_files: ['foo/*.js', 'bar/*.js'],
concat: {
// concat task configuration goes here.
},
uglify: {
// uglify task configuration goes here.
},
});
grunt.initConfig(
concat:
options:
# Task-level options, overriding defaults
development:
# development, $ grunt foo:development
options:
# "development" options, overriding task-level
production: # production, $ grunt foo:production
options:
# "production" options, overriding task-level
# Invoke with grunt foo cool:tapir
grunt.registerTask('foo', 'Foo description, (a, b) ->
grunt.log.witeln(this.name, a, b)
# Prints foo cool tapir
grunt.registerMultiTask('mytask', 'task description', function() {
// Iterate over all specified file groups.
this.files.forEach(function(f) {
// Do something with file
}
});
grunt.registerTask('asyncfoo', 'My "asyncfoo" task.', function() {
// Grab a handle to the "done" function.
var done = this.async();
// Run some sync stuff.
grunt.log.writeln('Processing task...');
// And some async stuff.
setTimeout(function() {
grunt.log.writeln('All done!');
done();
}, 1000);
});
Single src:
and dest:
grunt.initConfig({
jshint: {
foo: {
src: ['src/aa.js', 'src/aaa.js']
},
},
concat: {
bar: {
src: ['src/bb.js', 'src/bbb.js'],
dest: 'dest/b.js',
},
},
});
grunt.initConfig(
concat:
foo:
files:
'dest/a.js': ['src/aa.js', 'src/aaa.js']
'dest/a1.js': ['src/aa1.js', 'src/aaa1.js']
bar:
files:
'dest/b.js': ['src/bb.js', 'src/bbb.js']
'dest/b1.js': ['src/bb1.js', 'src/bbb1.js']
grunt.initConfig(
concat:
foo:
files: [
{src: ['src/client/*.js'], dest: 'dest/a.js'}
{src: ['src/server/**/*.js'], dest: 'dest/a1.js'}
]
bar:
files: [
{src: 'src/a.js', dest: 'dest/', filter: 'isFile'}
]
// You can specify single files:
{src: 'foo/this.js', dest: ...}
// Or arrays of files:
{src: ['foo/this.js', 'foo/that.js'], dest: ...}
// Or you can generalize with a glob pattern:
{src: 'foo/th*.js', dest: ...}
// All .js files, in foo/, in alpha order:
{src: ['foo/*.js'], dest: ...}
// Here, bar.js is first, remaining files, in alpha order:
{src: ['foo/bar.js', 'foo/*.js'], dest: ...}
// This single node-glob pattern:
{src: 'foo/{a,b}*.js', dest: ...}
// All files except for bar.js, in alpha order:
{src: ['foo/*.js', '!foo/bar.js'], dest: ...}
// All files in alpha order, but with bar.js at the end.
{src: ['foo/*.js', '!foo/bar.js', 'foo/bar.js'], dest: ...}
filter
grunt.initConfig({
clean: {
foo: {
src: ['tmp/**/*'],
filter: function(filepath) {
return grunt.file.isDir(filepath) &&
require('fs').readdirSync(filepath).length === 0;
}
}
}
});
expand
grunt.initConfig({
minify: {
dynamic_mappings: {
files: [
{
expand: true, // Enable dynamic expansion.
cwd: 'lib/', // Src are relative to this
src: ['**/*.js'], // Actual pattern(s) to match.
dest: 'build/', // Destination path prefix.
ext: '.min.js', // Dest files gets extension.
}
]}}});
grunt.initConfig({
concat: {
sample: {
options: {
banner: '/* <%= bar %> */\n',
},
src: ['<%= foo %>'],
},
},
// Properties are expanded recursively
foo: 'c',
bar: 'b<%= foo %>d', // 'bcd'
});
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
uglify: {
dist: {
src: 'src/<%= pkg.name %>.js',
dest: 'dist/<%= pkg.name %>.min.js'
}
}
});
watch
and livereload
grunt-contrib-watch
grunt-contrib-livereload
grunt.initConfig({
watch: {
scripts: {
files: ['**/*.js'],
tasks: ['livereload'],
options: {
nospawn: true,
}
}
}
grunt-contrib-requirejs
grunt-contrib-jshint
grunt-contrib-uglify
grunt-contrib-coffee
grunt-contrib-mocha
grunt-buster
grunt-contrib-jasmine
grunt-contrib-nodeunit
grunt-contrib-qunit
grunt-contrib-cssmin
grunt-contrib-csslint
grunt-contrib-concat
grunt-contrib-sass
grunt-contrib-less
grunt-contrib-stylus
grunt-contrib-compass
grunt-recess
grunt-contrib-handlebars
grunt-contrib-jade
grunt-contrib-jst
grunt-contrib-imagemin
grunt-imageoptim
grunt-image-resize
grunt-imagine
grunt-contrib-compress
grunt-contrib-copy
grunt-contrib-clean
grunt-contrib-htmlmin
grunt-s3