grunt.js - automate all the things!1!!

grunt.js - automate all the things!1!!

Talk from the second stahlstadt.js meetup

http://www.meetup.com/stahlstadt-js/events/143609572/

97c57e7e99431e76fbc04173cca51eab?s=128

Clemens Müller

December 11, 2013
Tweet

Transcript

  1. GRUNT.JS Automate all the things!!1!

  2. SE PROBLEM • remove debug statements like console.log • concatenate

    and minify JS files • run tests, JSHint • compile SASS, minify images, sprites, … • …
  3. APPROACHES manually • use existing infrastructure, like Rails Asset Pipeline,

    … • Makefile, Shell Scripts • Ant, Maven, Jake, Rake, …
  4. APPROACHES manually • use existing infrastructure, like Rails Asset Pipeline,

    … • Makefile, Shell Scripts • Ant, Maven, Jake, Rake, … • Grunt
  5. • The JavaScript Task Runner • node.js • Configuration over

    scripting • Plugins, which are mostly wrappers around existing libs WHAT IS GRUNT?
  6. • introduced by Ben @cowboy Alman • gruntjs.com / @gruntjs

    • v0.4.2 HARD FACTS
  7. None
  8. None
  9. brew install nodejs npm install grunt-cli --global

  10. GRUNTIFY A PROJECT • package.json • Gruntfile.js

  11. $ tree . 0 directories, 0 files

  12. // package.json 1 { 2 "name": "stahlstadtjs_grunt", 3 "version": "0.0.1",

    4 "author": "Thomas Brezina" 5 }
  13. npm install grunt --save-dev

  14. npm install grunt --save-dev 1 { 2 "name": "stahlstadtjs_grunt", 3

    "version": "0.0.1", 4 "author": "Thomas Brezina", 5 "devDependencies": { 6 "grunt": "~0.4.2" 7 } 8 }
  15. • Project and task configuration • Loading Grunt plugins and

    tasks • Custom tasks
  16. // Gruntfile.js 1 module.exports = function(grunt) { 2 }

  17. // Gruntfile.js 1 module.exports = function(grunt) { 2 } $

    grunt
  18. // Gruntfile.js 1 module.exports = function(grunt) { 2 } $

    grunt Warning: Task "default" not found. Use --force to continue. Aborted due to warnings.
  19. // Gruntfile.js 1 module.exports = function(grunt) { 2 grunt.registerTask("default", []);

    3 }
  20. // Gruntfile.js 1 module.exports = function(grunt) { 2 grunt.registerTask("default", []);

    3 } $ grunt
  21. // Gruntfile.js 1 module.exports = function(grunt) { 2 grunt.registerTask("default", []);

    3 } $ grunt Done without errors.
  22. . !"" Gruntfile.js #"" package.json

  23. // src/app.js 1 App = function() {} 2 App.prototype.greet =

    function(name) { 3 console.log("hello " + name) 4 }
  24. . !"" Gruntfile.js !"" package.json #"" src #"" app.js

  25. JSHINT npm install grunt-contrib-jshint --save-dev

  26. JSHINT npm install grunt-contrib-jshint --save-dev 1 { 2 "name": "stahlstadtjs_grunt",

    3 "version": "0.0.1", 4 "author": "Thomas Brezina", 5 "devDependencies": { 6 "grunt": "~0.4.2", 7 "grunt-contrib-jshint": "~0.7.2" 8 } 9 }
  27. 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 jshint: {

    4 all: ["src/*.js"] 5 } 6 }); 7 8 grunt.loadNpmTask("grunt-contrib-jshint"); 9 10 grunt.registerTask("default", ["jshint"]); 11 } JSHINT
  28. 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 jshint: {

    4 all: ["src/*.js"] 5 } 6 }); 7 8 grunt.loadNpmTask("grunt-contrib-jshint"); 9 10 grunt.registerTask("default", ["jshint"]); 11 } JSHINT
  29. JSHINT $ grunt

  30. JSHINT $ grunt Running "jshint:all" (jshint) task Linting src/app.js ...ERROR

    [L3:C31] W033: Missing semicolon. console.log("hello " + name) Warning: Task "jshint:all" failed. Use --force to continue. Aborted due to warnings.
  31. // src/app.js 1 App = function() {} 2 App.prototype.greet =

    function(name) { 3 console.log("hello " + name) 4 }
  32. // src/app.js 1 App = function() {} 2 App.prototype.greet =

    function(name) { 3 console.log("hello " + name) ; 4 }
  33. JSHINT $ grunt Running "jshint:all" (jshint) task >> 1 file

    lint free. Done, without errors.
  34. JSHINT $ grunt jshint Running "jshint:all" (jshint) task >> 1

    file lint free. Done, without errors.
  35. JSHINT $ grunt jshint Running "jshint:all" (jshint) task >> 1

    file lint free. Done, without errors. ProTip™ http://jslinterrors.com/
  36. UGLIFY npm install grunt-contrib-uglify --save-dev

  37. UGLIFY npm install grunt-contrib-uglify --save-dev 1 { 2 "name": "stahlstadtjs_grunt",

    3 "version": "0.0.1", 4 "author": "Thomas Brezina", 5 "devDependencies": { 6 "grunt": "~0.4.2", 7 "grunt-contrib-jshint": "~0.7.2", 8 "grunt-contrib-uglify": "~0.2.7" 9 } 10 }
  38. 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 jshint: {

    }, 4 uglify: { 5 debug: { 6 src: "src/app.js", 7 dest: "dist/app.js", 8 options: { beautify: true } 9 }, 10 minified: { 11 src: "src/app.js", 12 dest: "dist/app.min.js", 13 options: { mangle: true, compress: true } 14 } 15 } 16 }); 17 18 grunt.registerTask("default", ["jshint", "uglify"]); 19 20 grunt.loadNpmTasks("grunt-contrib-uglify"); 21 grunt.loadNpmTasks("grunt-contrib-jshint"); 22 }
  39. 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 jshint: {

    }, 4 uglify: { 5 debug: { 6 src: "src/app.js", 7 dest: "dist/app.js", 8 options: { beautify: true } 9 }, 10 minified: { 11 src: "src/app.js", 12 dest: "dist/app.min.js", 13 options: { mangle: true, compress: true } 14 } 15 } 16 }); 17 18 grunt.registerTask("default", ["jshint", "uglify"]); 19 20 grunt.loadNpmTasks("grunt-contrib-uglify"); 21 grunt.loadNpmTasks("grunt-contrib-jshint"); 22 }
  40. UGLIFY $ grunt uglify:minified Running "uglify: minified" (uglify) task File

    "dist/app.min.js" created. Done, without errors.
  41. UGLIFY $ grunt uglify:debug Running "uglify:debug" (uglify) task File "dist/app.js"

    created. Done, without errors.
  42. UGLIFY $ grunt uglify Running "uglify:debug" (uglify) task File "dist/app.js"

    created. Running "uglify:minified" (uglify) task File "dist/app.min.js" created. Done, without errors.
  43. UGLIFY . !"" Gruntfile.js !"" package.json #"" dist $ !""

    app.js $ #"" app.min.js #"" src #"" app.js
  44. 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 pkg: grunt.file.readJSON("package.json"),

    4 jshint: {}, 5 uglify: { 6 debug: { 7 src: "src/app.js", 8 dest: "dist/app-<%= pkg.version %>.js", 9 options: { beautify: true } 10 }, 11 minified: { 12 src: "src/app.js", 13 dest: "dist/app-<%= pkg.version %>.min.js", 14 options: { mangle: true, compress: true } 15 } 16 } 17 }); 18 19 grunt.registerTask("default", ["jshint", "uglify"]); 20 21 grunt.loadNpmTasks("grunt-contrib-uglify"); 22 grunt.loadNpmTasks("grunt-contrib-jshint"); 23 }
  45. 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 pkg: grunt.file.readJSON("package.json"),

    4 jshint: {}, 5 uglify: { 6 debug: { 7 src: "src/app.js", 8 dest: "dist/app-<%= pkg.version %>.js", 9 options: { beautify: true } 10 }, 11 minified: { 12 src: "src/app.js", 13 dest: "dist/app-<%= pkg.version %>.min.js", 14 options: { mangle: true, compress: true } 15 } 16 } 17 }); 18 19 grunt.registerTask("default", ["jshint", "uglify"]); 20 21 grunt.loadNpmTasks("grunt-contrib-uglify"); 22 grunt.loadNpmTasks("grunt-contrib-jshint"); 23 }
  46. UGLIFY $ grunt uglify Running "uglify:debug" (uglify) task File "dist/app-0.0.1.js"

    created. Running "uglify:minified" (uglify) task File "dist/app-0.0.1.min.js" created. Done, without errors.
  47. UGLIFY • sourcemaps • banner • conditional compilation • …

  48. UGLIFY . !"" Gruntfile.js !"" package.json #"" dist $ !""

    app-0.0.1.js $ !"" app-0.0.1.min.js $ !"" app.js $ #"" app.min.js #"" src #"" app.js
  49. CLEAN npm install grunt-contrib-clean --save-dev

  50. CLEAN npm install grunt-contrib-clean --save-dev 1 { 2 "name": "stahlstadtjs_grunt",

    3 "version": "0.0.1", 4 "author": "Thomas Brezina", 5 "devDependencies": { 6 "gruntnt": "~0.4.2", 7 "grunt-contrib-jshint": "~0.7.2", 8 "grunt-contrib-uglify": "~0.2.7" 9 "grunt-contrib-clean": "~0.5.0" 10 } 11 }
  51. CLEAN 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3 pkg:

    …, 4 jshint: { … }, 5 uglify: { … }, 6 clean: ["dist"] 7 }); 8 9 grunt.registerTask("default", ["jshint", "clean", "uglify"]); 10 11 grunt.loadNpmTasks("grunt-contrib-clean"); 12 grunt.loadNpmTasks("grunt-contrib-uglify"); 13 grunt.loadNpmTasks("grunt-contrib-jshint"); 14 }
  52. CLEAN $ grunt clean

  53. CLEAN $ grunt clean Running "clean:0" (clean) task Cleaning dist...OK

    Done, without errors.
  54. CLEAN . !"" Gruntfile.js !"" package.json #"" src #"" app.js

  55. ALLE 3 ZUSAMMEN $ grunt

  56. ALLE 3 ZUSAMMEN $ grunt Running "jshint:all" (jshint) task >>

    1 file lint free. Running "clean:0" (clean) task Cleaning dist...OK Running "uglify:debug" (uglify) task File "dist/app-0.0.1.js" created. Running "uglify:minified" (uglify) task File "dist/app-0.0.1.min.js" created. Done, without errors.
  57. MOAR PLUGINS • currently 1931 plugins • almost all start

    with grunt- • grunt-contrib-* are official plugins supported by core team • tip top README’s
  58. LOAD-GRUNT-TASKS 1 module.exports = function(grunt) { 2 grunt.loadNpmTasks("grunt-shell"); 3 grunt.loadNpmTasks("grunt-sass");

    4 grunt.loadNpmTasks("grunt-recess"); 5 grunt.loadNpmTasks("grunt-sizediff"); 6 grunt.loadNpmTasks("grunt-svgmin"); 7 grunt.loadNpmTasks("grunt-styl"); 8 grunt.loadNpmTasks("grunt-php"); 9 grunt.loadNpmTasks("grunt-eslint"); 10 grunt.loadNpmTasks("grunt-concurrent"); 11 grunt.loadNpmTasks("grunt-bower-requirejs"); 12 }
  59. LOAD-GRUNT-TASKS 1 module.exports = function(grunt) { 2 // load all

    grunt tasks matching the `grunt-*` pattern 3 require("load-grunt-tasks")(grunt); 4 }
  60. GRUNT-CONTRIB-CONCAT 1 grunt.initConfig({ 2 concat: { 3 dist: { 4

    src: ["src/main.js", "src/**/*.js"], 5 dest: "dist/app.js" 6 } 7 } 8 });
  61. GRUNT-NEUTER // a.js require("b"); new B(); // b.js require("c"); B

    = function() { new C(); } // c.js C = function() {} // d.js D = function() {}
  62. GRUNT-NEUTER // a.js require("b"); new B(); // b.js require("c"); B

    = function() { new C(); } // c.js C = function() {} // d.js D = function() {} // Gruntfile.js neuter: { src: ["a.js"], dest: "dist/app.js" } +
  63. GRUNT-NEUTER // a.js require("b"); new B(); // b.js require("c"); B

    = function() { new C(); } // c.js C = function() {} // d.js D = function() {} // dist/app.js C = function() {} B = function() { new C(); } new B(); // Gruntfile.js neuter: { src: ["a.js"], dest: "dist/app.js" } + =
  64. GRUNT-NEUTER // a.js require("b"); new B(); // b.js require("c"); B

    = function() { new C(); } // c.js C = function() {} // d.js D = function() {} // dist/app.js C = function() {} B = function() { new C(); } new B(); D = function() {} // Gruntfile.js neuter: { src: ["a.js", “*.js”], dest: "dist/app.js" } + =
  65. GRUNT-CONTRIB-WATCH grunt.initConfig({ watch: { gruntfile: { files: "Gruntfile.js", tasks: ["jshint:gruntfile"],

    }, src: { files: ["lib/*.js", "css/**/*.scss", "!lib/dontwatch.js"], tasks: ["default"], } } });
  66. GRUNT-NOTIFY • notifications • useful for tasks running in background

  67. GRUNT-NOTIFY • notifications • useful for tasks running in background

  68. SASS, LESS, STYLUS, ... • grunt-contrib-sass • grunt-sass • grunt-contrib-less

    • grunt-contrib-stylus
  69. GRUNT-CONTRIB-CONNECT grunt.initConfig({ connect: { server: { options: { port: 8000,

    base: "dist" } } } });
  70. GRUNT-CONTRIB-CONNECT grunt.initConfig({ connect: { server: { options: { port: 8000,

    base: "dist" } }, test: { options: { port: 8001, base: "test" } } } });
  71. GRUNT-CONTRIB-CONNECT • multiple servers • watch task & live-reload •

    grunt-connect-proxy • grunt-browser-sync
  72. ES6-MODULE-TRANSPILER • Tomorrow’s JavaScript module syntax today • https://github.com/joefiorini/grunt-es6-module-transpiler

  73. OTHER USEFUL PLUGINS • grunt-s3 • grunt-release • grunt-parallel, grunt-newer

    • grunt-remove-logging • mincss, uncss, csslint • imagemin, spritesmith • responsive-images • qunit, mocha, jasmine, CasperJS, SlimerJS, ... • http://gruntjs.com/plugins
  74. CUSTOM TASKS 1 module.exports = function(grunt) { 2 grunt.initConfig({ 3

    watch: { ... }, 4 connect: { 5 test: { ... } 6 } 7 }); 8 9 grunt.registerTask("test", ["connect:test", "watch"]); 10 }
  75. WRITING YOUR OWN TASK 1 module.exports = function(grunt) { 2

    grunt.registerTask("random", "a random number", function() { 3 var math = require("fast-random-number-NPM-module"); 4 grunt.log.writeln( math.random() ); 5 }); 6 }
  76. WRITING YOUR OWN TASK 1 module.exports = function(grunt) { 2

    grunt.registerTask("random", "a random number", function() { 3 var math = require("fast-random-number-NPM-module"); 4 grunt.log.writeln( math.random() ); 5 }); 6 }
  77. None
  78. 1 module.exports = function(grunt) { 2 // load needed grunt

    tasks from package.json 3 grunt.loadNpmTasks("grunt-contrib-clean"); 4 ...
  79. 1 module.exports = function(grunt) { 2 // load needed grunt

    tasks from package.json 3 grunt.loadNpmTasks("grunt-contrib-clean"); 4 ... 5 6 // configure the tasks 7 grunt.initConfig({ 8 jshint: { ... }, 9 ... 10 });
  80. 1 module.exports = function(grunt) { 2 // load needed grunt

    tasks from package.json 3 grunt.loadNpmTasks("grunt-contrib-clean"); 4 ... 5 6 // configure the tasks 7 grunt.initConfig({ 8 jshint: { ... }, 9 ... 10 }); 11 12 // specify default and custom tasks 13 grunt.registerTask("default", ["dist"]); 14 grunt.registerTask("dist", ["clean", "uglify"]); 15 grunt.registerTask("test", ["watch", "connect"]); 16 }
  81. 1 module.exports = function(grunt) { 2 // load needed grunt

    tasks from package.json 3 grunt.loadNpmTasks("grunt-contrib-clean"); 4 ... 5 6 // configure the tasks 7 grunt.initConfig({ 8 jshint: { ... }, 9 ... 10 }); 11 12 // specify default and custom tasks 13 grunt.registerTask("default", ["dist"]); 14 grunt.registerTask("dist", ["clean", "uglify"]); 15 grunt.registerTask("test", ["watch", "connect"]); 16 }
  82. 0.5.0 • split configurations since Gruntfile can get big #989

    • load-grunt-tasks, load-grunt-config • interactive CLI #949 • Make task file compilation more intelligent #927 • …
  83. PROJECTS WHICH MAKE GOOD USE OF GRUNT.JS • https://github.com/bevacqua/unbox •

    https://github.com/stefanpenner/ember-app-kit
  84. LINKS • http://tamas.io/introduction-to-grunt/ • http://merrickchristensen.com/articles/gruntjs-workflow.html • https://speakerdeck.com/ginader/let-grunt-do-the-work-focus-on- the-fun • https://speakerdeck.com/addyosmani/automating-front-end-

    workflow • http://blog.ponyfoo.com/2013/11/13/grunt-tips-and-tricks
  85. POSSIBLE NEXT TALK’S • by YOU?!!!! • split options for

    tasks into separate files • more examples • live reload, across browsers • requirejs, grunt-neuter • grunt & yeoman & bower • project scaffolding • grunt advanced patterns • tips’n’tricks • grunt in the wild
  86. DANK U VOOR UW AANDACHT. @pangratz @stahlstadtjs