Slide 1

Slide 1 text

GRUNT.JS Automate all the things!!1!

Slide 2

Slide 2 text

SE PROBLEM • remove debug statements like console.log • concatenate and minify JS files • run tests, JSHint • compile SASS, minify images, sprites, … • …

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

• The JavaScript Task Runner • node.js • Configuration over scripting • Plugins, which are mostly wrappers around existing libs WHAT IS GRUNT?

Slide 6

Slide 6 text

• introduced by Ben @cowboy Alman • gruntjs.com / @gruntjs • v0.4.2 HARD FACTS

Slide 7

Slide 7 text

No content

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

brew install nodejs npm install grunt-cli --global

Slide 10

Slide 10 text

GRUNTIFY A PROJECT • package.json • Gruntfile.js

Slide 11

Slide 11 text

$ tree . 0 directories, 0 files

Slide 12

Slide 12 text

// package.json 1 { 2 "name": "stahlstadtjs_grunt", 3 "version": "0.0.1", 4 "author": "Thomas Brezina" 5 }

Slide 13

Slide 13 text

npm install grunt --save-dev

Slide 14

Slide 14 text

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 }

Slide 15

Slide 15 text

• Project and task configuration • Loading Grunt plugins and tasks • Custom tasks

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

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

Slide 18

Slide 18 text

// Gruntfile.js 1 module.exports = function(grunt) { 2 } $ grunt Warning: Task "default" not found. Use --force to continue. Aborted due to warnings.

Slide 19

Slide 19 text

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

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

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

Slide 22

Slide 22 text

. !"" Gruntfile.js #"" package.json

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

. !"" Gruntfile.js !"" package.json #"" src #"" app.js

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

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 }

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

JSHINT $ grunt

Slide 30

Slide 30 text

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.

Slide 31

Slide 31 text

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

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

JSHINT $ grunt jshint Running "jshint:all" (jshint) task >> 1 file lint free. Done, without errors. ProTip™ http://jslinterrors.com/

Slide 36

Slide 36 text

UGLIFY npm install grunt-contrib-uglify --save-dev

Slide 37

Slide 37 text

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 }

Slide 38

Slide 38 text

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 }

Slide 39

Slide 39 text

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 }

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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.

Slide 43

Slide 43 text

UGLIFY . !"" Gruntfile.js !"" package.json #"" dist $ !"" app.js $ #"" app.min.js #"" src #"" app.js

Slide 44

Slide 44 text

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 }

Slide 45

Slide 45 text

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 }

Slide 46

Slide 46 text

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.

Slide 47

Slide 47 text

UGLIFY • sourcemaps • banner • conditional compilation • …

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

CLEAN npm install grunt-contrib-clean --save-dev

Slide 50

Slide 50 text

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 }

Slide 51

Slide 51 text

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 }

Slide 52

Slide 52 text

CLEAN $ grunt clean

Slide 53

Slide 53 text

CLEAN $ grunt clean Running "clean:0" (clean) task Cleaning dist...OK Done, without errors.

Slide 54

Slide 54 text

CLEAN . !"" Gruntfile.js !"" package.json #"" src #"" app.js

Slide 55

Slide 55 text

ALLE 3 ZUSAMMEN $ grunt

Slide 56

Slide 56 text

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.

Slide 57

Slide 57 text

MOAR PLUGINS • currently 1931 plugins • almost all start with grunt- • grunt-contrib-* are official plugins supported by core team • tip top README’s

Slide 58

Slide 58 text

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 }

Slide 59

Slide 59 text

LOAD-GRUNT-TASKS 1 module.exports = function(grunt) { 2 // load all grunt tasks matching the `grunt-*` pattern 3 require("load-grunt-tasks")(grunt); 4 }

Slide 60

Slide 60 text

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 });

Slide 61

Slide 61 text

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

Slide 62

Slide 62 text

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" } +

Slide 63

Slide 63 text

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" } + =

Slide 64

Slide 64 text

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" } + =

Slide 65

Slide 65 text

GRUNT-CONTRIB-WATCH grunt.initConfig({ watch: { gruntfile: { files: "Gruntfile.js", tasks: ["jshint:gruntfile"], }, src: { files: ["lib/*.js", "css/**/*.scss", "!lib/dontwatch.js"], tasks: ["default"], } } });

Slide 66

Slide 66 text

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

Slide 67

Slide 67 text

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

Slide 68

Slide 68 text

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

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

GRUNT-CONTRIB-CONNECT • multiple servers • watch task & live-reload • grunt-connect-proxy • grunt-browser-sync

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

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

Slide 74

Slide 74 text

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 }

Slide 75

Slide 75 text

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 }

Slide 76

Slide 76 text

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 }

Slide 77

Slide 77 text

No content

Slide 78

Slide 78 text

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

Slide 79

Slide 79 text

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 });

Slide 80

Slide 80 text

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 }

Slide 81

Slide 81 text

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 }

Slide 82

Slide 82 text

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 • …

Slide 83

Slide 83 text

PROJECTS WHICH MAKE GOOD USE OF GRUNT.JS • https://github.com/bevacqua/unbox • https://github.com/stefanpenner/ember-app-kit

Slide 84

Slide 84 text

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

Slide 85

Slide 85 text

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

Slide 86

Slide 86 text

DANK U VOOR UW AANDACHT. @pangratz @stahlstadtjs