Let Grunt do the work,
   focus on the fun!
    Dirk Ginader, Google, 2013




                                 1
Let Grunt do the endlessly
repetitive tedious tasks, focus
   on the important stuff!
       Dirk Ginader, Google, 2013




                                    2
Let Grunt do the work,
   focus on the fun!
    Dirk Ginader, Google, 2013




                                 3
Why Build scripts?



                     4
Because great
 Developers
  are lazy.


                5
Because great
 Developers
  are lazy.
   FACT.

                6
runs script
time                                  loses
spent   writes script
        to automate
                                                  wins
         gets
         annoyed                       makes fun of geek’s
                                       complicated method
        does it
        manually


 geek              does it manually

        non-geek                              task size


                                                             7
Build systems have
    been around for ages
•   Make                   •   Ant

•   Maven                  •   Rake

•   and so many more ...




                                      8
They’re all great and
 powerful and all...


                        9
Minify with Ant
<target name="js-compile-all" description="Compile JavaScript files with Closure"
unless="skip-js-compile">
    <echo>Compiling JS files in ${input.scripts.dir} in closure...</echo>
    <apply executable="java" dest="${output.scripts.dir}">
        <arg value="-jar"/>
        <arg path="${jar.lib.dir}/closure-compiler.jar"/>
        <arg line="--js"/>
        <srcfile/>
        <arg line="--js_output_file"/>
        <targetfile/>
        <fileset dir="${output.scripts.dir}" includes="**/*-main.debug.js" />
        <mapper type="glob" from="*-main.debug.js" to="*-main.min.js"/>
    </apply>
    <echo>Finished compiling JS files</echo>
</target>




            http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/

                                                                                                              10
11
How much I liked to
configure with XML?


                      12
13
I’m a Front End
  Developer!


                  14
I like Javascript



                    15
I like LOVE Javascript



                         16
17
Just one year ago
Ben Alman did me a
    great favor:


                     18
GRUNT
The JavaScript Task Runner


                             19
20
written in Javascript



                        21
using the node
package manager


                  22
FAST adoption rate
•   jQuery

•   Modernizr

•   Adobe

•   twitter

•   ...




                          23
because it’s easy!



                     24
System Setup:



                25
download and install
   node.js from:
 http://nodejs.org/


                       26
$ npm install -g grunt-cli




                             27
Project Setup:



                 28
2 important Files:
   package.json
    Gruntfile.js


                     29
package.json



               30
{
    "name": "jQuery-Accessible-Tabs",
    "version": "1.9.7",
    "homepage": "http://github.com/ginader/Accessible-Tabs",
    "author": {
      "name": "Dirk Ginader",
      "url": "http://ginader.com"
    },
    "devDependencies": {

    }
}




                         https://npmjs.org/doc/json.html
                                                               31
Gives you:

• Variables you can use in your script
  i.e. version and name
• Dev Dependencies that allows you to
  quickly install all required npm modules




                                             32
{
    "name": "jQuery-Accessible-Tabs",
    "version": "1.9.7",
    "homepage": "http://github.com/ginader/Accessible-Tabs",
    "author": {
      "name": "Dirk Ginader",
      "url": "http://ginader.com"
    },
    "devDependencies": {

    }
}




                         https://npmjs.org/doc/json.html
                                                               33
$ npm install grunt --save-dev




                                 34
{
    "name": "jQuery-Accessible-Tabs",
    "version": "1.9.7",
    "homepage": "http://github.com/ginader/Accessible-Tabs",
    "author": {
      "name": "Dirk Ginader",
      "url": "http://ginader.com"
    },
    "devDependencies": {
      "grunt": "~0.4.0"
    }
}




                         https://npmjs.org/doc/json.html
                                                               35
install all the defined
     Dependencies in one go

$ npm install




                               36
Gruntfile.js



              37
Minify with Grunt
  module.exports = function(grunt) {
     grunt.initConfig({
       uglify: {
         dist: {
           src: 'dist/myfile.js',
           dest: 'dist/myfile.min.js'
         },
       }
     });
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.registerTask('default', ['uglify']);
  };




http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/

                                                                                                  38
Minify with Ant
<target name="js-compile-all" description="Compile JavaScript files with Closure"
unless="skip-js-compile">
    <echo>Compiling JS files in ${input.scripts.dir} in closure...</echo>
    <apply executable="java" dest="${output.scripts.dir}">
        <arg value="-jar"/>
        <arg path="${jar.lib.dir}/closure-compiler.jar"/>
        <arg line="--js"/>
        <srcfile/>
        <arg line="--js_output_file"/>
        <targetfile/>
        <fileset dir="${output.scripts.dir}" includes="**/*-main.debug.js" />
        <mapper type="glob" from="*-main.debug.js" to="*-main.min.js"/>
    </apply>
    <echo>Finished compiling JS files</echo>
</target>




            http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/

                                                                                                              39
40
Minify with Grunt
  module.exports = function(grunt) {
     grunt.initConfig({
       uglify: {
         dist: {
           src: 'dist/myfile.js',
           dest: 'dist/myfile.min.js'
         }
       }
     });
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.registerTask('default', ['uglify']);
  };




http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/

                                                                                                  41
Minify with Grunt
  module.exports = function(grunt) {
     grunt.initConfig({
       uglify: {
         dist: {
           src: 'dist/myfile.js',
           dest: 'dist/myfile.min.js'
         }
       }
     });
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.registerTask('default', ['uglify']);
  };




http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/

                                                                                                  42
Minify with Grunt
  module.exports = function(grunt) {
     grunt.initConfig({
       uglify: {
         dist: {
           src: 'dist/myfile.js',
           dest: 'dist/myfile.min.js'
         }
       }
     });
     grunt.loadNpmTasks('grunt-contrib-uglify');
     grunt.registerTask('default', ['uglify']);
  };




http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/

                                                                                                  43
44
easy to add more
$ npm i grunt-contrib-jshint --save-dev




                                          45
add JS Linting
module.exports = function(grunt) {
   grunt.initConfig({
     jshint: {
        all: ['*.js']
     },
     uglify: {
        dist: {
          src: 'myfile.js',
          dest: 'myfile.min.js'
        }
     }
   });
   grunt.loadNpmTasks('grunt-contrib-uglify');
   grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.registerTask('default', ['jshint','uglify']);
};




                                                         46
add data from package.json
module.exports = function(grunt) {
   grunt.initConfig({
     pkg: grunt.file.readJSON('package.json'),
     jshint: {
        all: ['*.js']
     },
     uglify: {
       options: {
          banner: '/*! <%= pkg.name %>' +
             ' <%= grunt.template.today("yyyy-mm-dd") %> */n'
        },
        dist: {
           src: 'myfile.js',
           dest: 'myfile.min.js'
        }
     }
   });
   grunt.loadNpmTasks('grunt-contrib-uglify');
   grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.registerTask('default', ['jshint','uglify']);
};



                                                                 47
add data from package.json
module.exports = function(grunt) {
   grunt.initConfig({
     pkg: grunt.file.readJSON('package.json'),
     jshint: {
        all: ['*.js']
     },
     uglify: {
        options: {
           banner: '/*! <%= pkg.name %>' +
             ' <%= grunt.template.today("yyyy-mm-dd") %> */n'
        },
        dist: {
           src: '<%= pkg.name %>.js',
           dest: '<%= pkg.name %>.min.js'
        }
     }
   });
   grunt.loadNpmTasks('grunt-contrib-uglify');
   grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.registerTask('default', ['jshint','uglify']);
};



                                                                 48
add data from package.json
module.exports = function(grunt) {
   grunt.initConfig({
     pkg: grunt.file.readJSON('package.json'),
     jshint: {
        all: ['*.js']
     },
     uglify: {
        options: {
           banner: '/*! <%= pkg.name %>' +
             ' <%= grunt.template.today("yyyy-mm-dd") %> */n'
        },
        dist: {
           src: '<%= pkg.name %>.js',
           dest: '<%= pkg.name %>.<%= pkg.version %>.min.js'
        }
     }
   });
   grunt.loadNpmTasks('grunt-contrib-uglify');
   grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.registerTask('default', ['jshint','uglify']);
};



                                                                 49
minify and combine CSS
  cssmin: {
    compress: {
      options: {
        banner: '<%= banner %>'
      },
      files: {
        'project.min.css': ['1.css','2.css', '...']
      }
    }
  }


grunt.loadNpmTasks('grunt-contrib-cssmin');

grunt.registerTask('default', ['jshint','uglify', 'cssmin']);




                                                                50
optimize Images
imagemin: {
  dist: {
    options: {
      optimizationLevel: 3
    },
    files: {
      // 'destination': 'source'
      'dist/img.png': 'src/img.png',
      'dist/img.jpg': 'src/img.jpg'
    }
  }
}

grunt.registerTask('default', ['imagemin']);




                                               51
but it’s more than just
     optimizations


                          52
render markdown to
       HTML
markdown: {
  all: {
    files: ['readme.markdown','version-history.markdown'],
    template: 'web/template.html',
    dest: 'web',
    options: {
      gfm: true,
      codeLines: {
         before: '<span>',
         after: '</span>'
      }
    }
  }
}




                                                             53
remove debug code
   removelogging: {
     dist: {
       src: 'js/jquery.tabs.min.js',
       dest: 'js/jquery.tabs.min.js'
     }
   }




                                       54
compile Sass/Compass
 // setup Compass/Sass to load from existing config.rb
 compass: {
   dist: {
     options: {
       config: 'config.rb'
     }
   }
 }




                                                         55
and Livereload!




                  56
Scaffolding



              57
$ npm install -g grunt-init




                              58
many templates for
          grunt-init
•   Gruntfile

•   Grunt plugin

•   jQuery plugin

•   node.js

•   ...




                           59
$ git clone git://
github.com/gruntjs/grunt-
init-jquery.git ~/.grunt-
init/jquery




                            60
$ grunt-init jquery




                      61
62
Thank you! Questions?

The opinions I expressed here represent my own
   and not necessarily those of my employer.

        btw: We’re hiring! Talk to me :-)
                                                 63
Resources
•   Grunt: http://gruntjs.com/
•   Great article: http://dir.kg/grunt.workflow
•   Extending Grunt big time: http://yeoman.io
•   Me: http://dir.kg/me
    •   @ginader on twitter
    •   the example projects: http://github.com/ginader/
    •   http://ginader.com


                                                           64

Let Grunt do the work, focus on the fun!

  • 1.
    Let Grunt dothe work, focus on the fun! Dirk Ginader, Google, 2013 1
  • 2.
    Let Grunt dothe endlessly repetitive tedious tasks, focus on the important stuff! Dirk Ginader, Google, 2013 2
  • 3.
    Let Grunt dothe work, focus on the fun! Dirk Ginader, Google, 2013 3
  • 4.
  • 5.
  • 6.
    Because great Developers are lazy. FACT. 6
  • 7.
    runs script time loses spent writes script to automate wins gets annoyed makes fun of geek’s complicated method does it manually geek does it manually non-geek task size 7
  • 8.
    Build systems have been around for ages • Make • Ant • Maven • Rake • and so many more ... 8
  • 9.
    They’re all greatand powerful and all... 9
  • 10.
    Minify with Ant <targetname="js-compile-all" description="Compile JavaScript files with Closure" unless="skip-js-compile"> <echo>Compiling JS files in ${input.scripts.dir} in closure...</echo> <apply executable="java" dest="${output.scripts.dir}"> <arg value="-jar"/> <arg path="${jar.lib.dir}/closure-compiler.jar"/> <arg line="--js"/> <srcfile/> <arg line="--js_output_file"/> <targetfile/> <fileset dir="${output.scripts.dir}" includes="**/*-main.debug.js" /> <mapper type="glob" from="*-main.debug.js" to="*-main.min.js"/> </apply> <echo>Finished compiling JS files</echo> </target> http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/ 10
  • 11.
  • 12.
    How much Iliked to configure with XML? 12
  • 13.
  • 14.
    I’m a FrontEnd Developer! 14
  • 15.
  • 16.
    I like LOVEJavascript 16
  • 17.
  • 18.
    Just one yearago Ben Alman did me a great favor: 18
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
    FAST adoption rate • jQuery • Modernizr • Adobe • twitter • ... 23
  • 24.
  • 25.
  • 26.
    download and install node.js from: http://nodejs.org/ 26
  • 27.
    $ npm install-g grunt-cli 27
  • 28.
  • 29.
    2 important Files: package.json Gruntfile.js 29
  • 30.
  • 31.
    { "name": "jQuery-Accessible-Tabs", "version": "1.9.7", "homepage": "http://github.com/ginader/Accessible-Tabs", "author": { "name": "Dirk Ginader", "url": "http://ginader.com" }, "devDependencies": { } } https://npmjs.org/doc/json.html 31
  • 32.
    Gives you: • Variablesyou can use in your script i.e. version and name • Dev Dependencies that allows you to quickly install all required npm modules 32
  • 33.
    { "name": "jQuery-Accessible-Tabs", "version": "1.9.7", "homepage": "http://github.com/ginader/Accessible-Tabs", "author": { "name": "Dirk Ginader", "url": "http://ginader.com" }, "devDependencies": { } } https://npmjs.org/doc/json.html 33
  • 34.
    $ npm installgrunt --save-dev 34
  • 35.
    { "name": "jQuery-Accessible-Tabs", "version": "1.9.7", "homepage": "http://github.com/ginader/Accessible-Tabs", "author": { "name": "Dirk Ginader", "url": "http://ginader.com" }, "devDependencies": { "grunt": "~0.4.0" } } https://npmjs.org/doc/json.html 35
  • 36.
    install all thedefined Dependencies in one go $ npm install 36
  • 37.
  • 38.
    Minify with Grunt module.exports = function(grunt) { grunt.initConfig({ uglify: { dist: { src: 'dist/myfile.js', dest: 'dist/myfile.min.js' }, } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['uglify']); }; http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/ 38
  • 39.
    Minify with Ant <targetname="js-compile-all" description="Compile JavaScript files with Closure" unless="skip-js-compile"> <echo>Compiling JS files in ${input.scripts.dir} in closure...</echo> <apply executable="java" dest="${output.scripts.dir}"> <arg value="-jar"/> <arg path="${jar.lib.dir}/closure-compiler.jar"/> <arg line="--js"/> <srcfile/> <arg line="--js_output_file"/> <targetfile/> <fileset dir="${output.scripts.dir}" includes="**/*-main.debug.js" /> <mapper type="glob" from="*-main.debug.js" to="*-main.min.js"/> </apply> <echo>Finished compiling JS files</echo> </target> http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/ 39
  • 40.
  • 41.
    Minify with Grunt module.exports = function(grunt) { grunt.initConfig({ uglify: { dist: { src: 'dist/myfile.js', dest: 'dist/myfile.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['uglify']); }; http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/ 41
  • 42.
    Minify with Grunt module.exports = function(grunt) { grunt.initConfig({ uglify: { dist: { src: 'dist/myfile.js', dest: 'dist/myfile.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['uglify']); }; http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/ 42
  • 43.
    Minify with Grunt module.exports = function(grunt) { grunt.initConfig({ uglify: { dist: { src: 'dist/myfile.js', dest: 'dist/myfile.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['uglify']); }; http://mechanics.flite.com/blog/2012/06/19/why-we-use-node-dot-js-and-grunt-to-build-javascript/ 43
  • 44.
  • 45.
    easy to addmore $ npm i grunt-contrib-jshint --save-dev 45
  • 46.
    add JS Linting module.exports= function(grunt) { grunt.initConfig({ jshint: { all: ['*.js'] }, uglify: { dist: { src: 'myfile.js', dest: 'myfile.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.registerTask('default', ['jshint','uglify']); }; 46
  • 47.
    add data frompackage.json module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), jshint: { all: ['*.js'] }, uglify: { options: { banner: '/*! <%= pkg.name %>' + ' <%= grunt.template.today("yyyy-mm-dd") %> */n' }, dist: { src: 'myfile.js', dest: 'myfile.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.registerTask('default', ['jshint','uglify']); }; 47
  • 48.
    add data frompackage.json module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), jshint: { all: ['*.js'] }, uglify: { options: { banner: '/*! <%= pkg.name %>' + ' <%= grunt.template.today("yyyy-mm-dd") %> */n' }, dist: { src: '<%= pkg.name %>.js', dest: '<%= pkg.name %>.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.registerTask('default', ['jshint','uglify']); }; 48
  • 49.
    add data frompackage.json module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), jshint: { all: ['*.js'] }, uglify: { options: { banner: '/*! <%= pkg.name %>' + ' <%= grunt.template.today("yyyy-mm-dd") %> */n' }, dist: { src: '<%= pkg.name %>.js', dest: '<%= pkg.name %>.<%= pkg.version %>.min.js' } } }); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.registerTask('default', ['jshint','uglify']); }; 49
  • 50.
    minify and combineCSS cssmin: { compress: { options: { banner: '<%= banner %>' }, files: { 'project.min.css': ['1.css','2.css', '...'] } } } grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.registerTask('default', ['jshint','uglify', 'cssmin']); 50
  • 51.
    optimize Images imagemin: { dist: { options: { optimizationLevel: 3 }, files: { // 'destination': 'source' 'dist/img.png': 'src/img.png', 'dist/img.jpg': 'src/img.jpg' } } } grunt.registerTask('default', ['imagemin']); 51
  • 52.
    but it’s morethan just optimizations 52
  • 53.
    render markdown to HTML markdown: { all: { files: ['readme.markdown','version-history.markdown'], template: 'web/template.html', dest: 'web', options: { gfm: true, codeLines: { before: '<span>', after: '</span>' } } } } 53
  • 54.
    remove debug code removelogging: { dist: { src: 'js/jquery.tabs.min.js', dest: 'js/jquery.tabs.min.js' } } 54
  • 55.
    compile Sass/Compass //setup Compass/Sass to load from existing config.rb compass: { dist: { options: { config: 'config.rb' } } } 55
  • 56.
  • 57.
  • 58.
    $ npm install-g grunt-init 58
  • 59.
    many templates for grunt-init • Gruntfile • Grunt plugin • jQuery plugin • node.js • ... 59
  • 60.
    $ git clonegit:// github.com/gruntjs/grunt- init-jquery.git ~/.grunt- init/jquery 60
  • 61.
  • 62.
  • 63.
    Thank you! Questions? Theopinions I expressed here represent my own and not necessarily those of my employer. btw: We’re hiring! Talk to me :-) 63
  • 64.
    Resources • Grunt: http://gruntjs.com/ • Great article: http://dir.kg/grunt.workflow • Extending Grunt big time: http://yeoman.io • Me: http://dir.kg/me • @ginader on twitter • the example projects: http://github.com/ginader/ • http://ginader.com 64