GruntJS The JavaScript Task Runner What is Grunt? • A build tool for JavaScript • Uses Node to run • A Gruntfile is actually just a JavaScript file • Therefore, you can code directly in the Gruntfile Getting Started with Grunt • Must create a package.json file { "name": "my-project-name", "version": "0.1.0", "devDependencies": { "grunt": "~0.4.2", "grunt-contrib-jshint": "~0.6.3", "grunt-contrib-jasmine": "~0.6.1", "grunt-contrib-uglify": "~0.2.2" } • Has the following attributes: • name • version • devDependencies • You can use npm init or the grunt-init package to generate one • For more optional attributes see https://npmjs.org/doc/json.html } Installing Grunt • In the folder with package.json, run npm install • This will install grunt, its dependencies, and any packages in devDependencies locally in that folder • To add plugins later use npm install <module-name> --save-dev • This will update package.json and install the plugin Writing a Gruntfile module.exports = function(grunt) { • A Gruntfile is a JavaScript file with the following parts • • • • A wrapper function The config object Plugin loading Custom tasks // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! Hello*/\n' }, build: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' } } }); // Load the plugin with the "uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['uglify']); }; Grunt Plugins • All tasks are provided by plugins • A plugin is a node module • A list can be found at http://gruntjs.com/plugins • contrib plugins are “official” • Some plugins you might need are • • • • contrib-concat contrib-uglify contrib-jasmine contrib-yuidoc Grunt Plugins • All tasks are provided by plugins • A plugin is a node module • A list can be found at http://gruntjs.com/plugins • contrib plugins are “official” • Install a plugin: • npm install <plugin> --save-dev • Add grunt.loadNpmTasks(<plugin>) to your Gruntfile • Some plugins you might need are • • • • contrib-concat contrib-uglify contrib-jasmine contrib-yuidoc Setting Task Options • Each plugin defines a task (or tasks) • Tasks are named for the action they take (jasmine, concat, etc.) • Each task can have multiple targets • Targets are named however you like • Options can be set at the task level or target level // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> */\n' }, dostuff: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js', options: { wrap: true } } } }); File Options • Options that specify files have several formats: • src as a property of the target • destination as the key with the source files as the value on a file object • An array of objects with src/dest properties • Can use *, **, ?, ! and {} for pattern matching mytarget:{ src: ['a.js', 'b.js'] dest: ['c.js'] } mytarget: { files: { 'output.js': ['src/*.js'], 'test_output.js': ['test/**/*.js'] } } mytarget: { files: [ {src: ['a.js', 'b.js'], dest: 'c.js'}, {src: ['ii.js'], dest: 'i.js', filter: 'isFile'} ] } The Jasmine Task • This task runs Jasmine tests on the command line • Important Options: • src: the JavaScript files you are testing • options.specs: your Jasmine testing specs • options.template: the template for your HTML jasmine: { mytarget: { src: 'src/**/*.js', options: { specs: 'tests/*Spec.js', template: 'mytemplate.tmpl' } } } Creating a Template • The Jasmine plugin uses underscore • You have a couple options: • Generate all your HTML dynamically • Create a template that adds Jasmine when a flag is passed • Copy and paste your HTML into a template every time you change it <!doctype html> <html> <head> <meta charset="utf-8"> <title>Jasmine Spec Runner</title> <% css.forEach(function(style){ %> <link rel="stylesheet" type="text/css" href="<%= style %>"> <% }) %> <% with (scripts) { %> <% [].concat(polyfills, jasmine, boot, vendor, helpers, src, specs,reporters).forEach(function(script){ %> <script src="<%= script %>"></script> <% }) %> <% }; %> </head> <body> </body> </html> Using YUIDoc • YUIDoc parses tags in /** special comments */ • Tags start with @ • • • • • • • @class @method @event @param @property @type @default /** * Class description * * @class MyClass * @constructor */ /** * Method description * * @method methodName * @param {String} foo Argument 1 * @param {Object} config A config object * @param {String} config.name The name on the config object * @param {Function} config.callback A callback function on the config object * @param {Boolean} [extra=false] Do extra, optional work * @return {Boolean} Returns true on success */ /** * Property description. * * @property propertyName * @type {Object} * @default "foo" */ YUIDoc Tags • @module is for a collection of related classes • Must have at least one per source tree • @class is for a function that generates an object or includes events • You must have at least one per file • @method is for a function on an object • @event is for a callback • The others give additional information about each of these The YUIDoc Task • The only important options are paths and outdir • The rest just help the document look pretty. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), yuidoc: { mytarget: { name: '<%= pkg.name %>', description: '<%= pkg.description %>', version: '<%= pkg.version %>', url: '<%= pkg.homepage %>', options: { paths: 'path/to/source/code/', outdir: 'where/to/save/docs/' } } } }); Exercise 1. Download demo.tar from the website (or copy it from /var/www/html on the server) 2. Copy Gruntfile.js and package.json to your own project 3. Run npm install to install grunt and the necessary plugins 4. Modify the grunt file to do something with your application