Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Front-end tooling with Grunt, Gulp and Yeoman - JavaScript Days 2014

Front-end tooling with Grunt, Gulp and Yeoman - JavaScript Days 2014

Slides from my 3hr workshop on front-end tooling with yeoman, grunt and gulp. Be sure to check some samples on https://github.com/ddprrt/tooling-workshop and https://github.com/ddprrt/generator-netural

Stefan Baumgartner

March 07, 2014
Tweet

More Decks by Stefan Baumgartner

Other Decks in Technology

Transcript

  1. Frontend Tooling with
    Grunt / Gulp / Yeoman
    Workshop
    JavaScript Days Munich, March 2014

    View Slide

  2. https://github.com/ddprrt/tooling-workshop
    https://github.com/ddprrt/generator-netural
    https://fettblog.eu
    Workshop samples

    View Slide

  3. Servus

    View Slide

  4. View Slide

  5. @ddprrt

    View Slide

  6. Netural

    View Slide

  7. workingdraft.de

    View Slide

  8. View Slide

  9. Our development stack

    View Slide

  10. Sass
    LESS
    Stylus
    CoffeeScript
    TypeScript
    JSHint
    JSLint HAML Jade
    Uglify
    CSSMIN
    ImageOptim
    Jasmine
    Mocha
    Proxy Connections
    Server
    Deployment CI/CD

    View Slide

  11. View Slide

  12. View Slide

  13. View Slide

  14. I should use a tool

    View Slide

  15. View Slide

  16. !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !

    View Slide

  17. !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !

    View Slide

  18. !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    1530 lines of code

    View Slide

  19. !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    1530 lines of code
    Original Ant tasks used:

    View Slide

  20. !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    !
    1530 lines of code
    Original Ant tasks used:
    concat - copy - delete - mkdir

    View Slide

  21. View Slide

  22. View Slide

  23. In the end, I realized that a task-based build tool
    with built-in, commonly used tasks was the
    approach that would work best for me.
    Unfortunately, I couldn’t find a build tool that
    worked the way that I wanted. So I built one.
    — Ben Alman, 2012

    View Slide

  24. View Slide

  25. eco system

    View Slide

  26. View Slide

  27. Runtime Environment
    JavaScript

    View Slide

  28. View Slide

  29. package manager
    each module is installed via npm
    grunt and grunt plugins

    View Slide

  30. grunt provides an interface to
    node modules
    grunt plugins are usually just a
    wrapper

    View Slide

  31. npm install -g grunt-cli
    npm init
    touch Gruntfile.js

    View Slide

  32. to the command line!

    View Slide

  33. to the command line!

    View Slide

  34. npm install --save-dev grunt-contrib-*
    npm install --save-dev grunt

    View Slide

  35. • parameter --save-dev adds modules to
    package.json
    • node_modules holds all the installed modules
    • npm install takes package.json to install
    required modules

    View Slide

  36. 'use strict';
    !
    module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-uglify');
    !
    grunt.initConfig({
    uglify: {
    dist: {
    files: [{
    'scripts/main.min.js' : ['scripts/main.js']
    }]
    }
    }
    });
    !
    grunt.registerTask('default', [
    'uglify'
    ]);
    };

    View Slide

  37. 'use strict';
    !
    module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-uglify');
    !
    grunt.initConfig({
    uglify: {
    dist: {
    files: [{
    'scripts/main.min.js' : ['scripts/main.js']
    }]
    }
    }
    });
    !
    grunt.registerTask('default', [
    'uglify'
    ]);
    };
    task

    View Slide

  38. 'use strict';
    !
    module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-uglify');
    !
    grunt.initConfig({
    uglify: {
    dist: {
    files: [{
    'scripts/main.min.js' : ['scripts/main.js']
    }]
    }
    }
    });
    !
    grunt.registerTask('default', [
    'uglify'
    ]);
    };
    task
    target

    View Slide

  39. 'use strict';
    !
    module.exports = function(grunt) {
    grunt.loadNpmTasks('grunt-contrib-uglify');
    !
    grunt.initConfig({
    uglify: {
    dist: {
    files: [{
    'scripts/main.min.js' : ['scripts/main.js']
    }]
    }
    }
    });
    !
    grunt.registerTask('default', [
    'uglify'
    ]);
    };
    task
    target
    options

    View Slide

  40. • registerTask registers a sequence of tasks!
    • grunt calls default task

    grunt build calls build task
    • initConfig takes an object of task definitions
    • loadNpmTasks loads one installed task

    has to be defined in package.json!

    View Slide

  41. View Slide

  42. View Slide

  43. basic tasks

    View Slide

  44. contrib tasks

    View Slide

  45. Sass
    LESS
    Stylus
    CoffeeScript
    TypeScript
    JSHint
    JSLint HAML Jade
    Uglify
    CSSMIN
    ImageOptim
    Jasmine
    Mocha
    Proxy Connections
    Server
    Deployment CI/CD

    View Slide

  46. Sass
    LESS
    Stylus
    CoffeeScript
    TypeScript
    JSHint
    JSLint HAML Jade
    Uglify
    CSSMIN
    ImageOptim
    Jasmine
    Mocha
    Proxy Connections
    Server
    Deployment CI/CD

    View Slide

  47. View Slide

  48. View Slide

  49. View Slide

  50. View Slide

  51. View Slide

  52. connect

    View Slide

  53. Connect
    Connect is a middleware framework for node,
    shipping with over 18 bundled middleware and a rich
    selection of 3rd-party middleware.

    View Slide

  54. connect.static
    connect.directory
    connect.static
    connect.session

    View Slide

  55. connect.static
    connect.directory
    Request
    cannot GET
    Response OK
    Response OK

    View Slide

  56. connect: {
    server: {
    options: {
    port: 9009,
    base: '.',
    hostname: ‘0.0.0.0’,
    keepalive: true
    }
    }
    },

    View Slide

  57. Problem?
    Keep the server alive indefinitely. Note that if this option
    is enabled, any tasks specified after this task will never
    run. By default, once grunt's tasks have completed, the
    web server stops. This option changes that behavior.

    View Slide

  58. connect + watch

    View Slide

  59. grunt.loadNpmTasks('grunt-contrib-connect');
    grunt.loadNpmTasks(‘grunt-contrib-watch');
    !
    grunt.registerTask('serve', [
    'connect:server',
    'watch'
    ]);

    View Slide

  60. watch: {
    scripts: {
    files: ['scripts/*.js'],
    tasks: ['jshint', 'uglify']
    },
    },

    View Slide

  61. connect.static
    connect.directory
    livereload
    Request
    Response OK!
    Response Injected

    View Slide

  62. connect: {
    server: {
    options: {
    port: 9009,
    base: '.',
    hostname: ‘0.0.0.0’,
    keepalive: true
    }
    }
    },

    View Slide

  63. connect: {
    server: {
    options: {
    port: 9009,
    base: '.',
    hostname: ‘0.0.0.0’,
    livereload: 35729, open: true
    }
    }
    },

    View Slide

  64. middlewares

    View Slide

  65. return function(req, res, next) {
    if(/* req fulfills some condition */) {
    /* do something */
    res.write(stdout);
    res.end();
    } else {
    next(); /* next middleware in stack */
    }
    }

    View Slide

  66. https://github.com/ddprrt/connect-php
    https://www.npmjs.org/package/connect-php
    http://fettblog.eu/blog/2013/11/17/the-magic-of-grunt-
    contrib-connect-and-how-to-run-php-with-it/

    View Slide

  67. CI / CD

    View Slide

  68. Yes, we can!

    View Slide

  69. Development Distribution
    Server + Livereload + Watch
    Sass —> TMP
    JS Unminified
    Assemble —> TMP
    Linting

    View Slide

  70. Development Distribution
    Server + Livereload + Watch
    Sass —> TMP
    JS Unminified
    Assemble —> TMP
    Linting
    Sass —> DIST
    JS Concat —> DIST + Minify
    Assemble —> DIST
    Linting
    Usemin

    View Slide

  71. grunt.initConfig({
    // configurable paths
    yeoman: {
    app: 'app',
    dist: 'dist'
    },

    });

    View Slide

  72. sass: {
    dist: {
    options: {
    style: 'compressed'
    },
    files: {
    '<%= yeoman.dist %>/styles/main.css':
    '<%= yeoman.app %>/styles/main.scss'
    }
    }
    ...

    View Slide

  73. ...
    server: {
    options: {
    style: ‘expanded’,
    debugInfo: true
    },
    files: {
    ‘.tmp/styles/main.css':
    '<%= yeoman.app %>/styles/main.scss'
    }
    }
    }

    View Slide

  74. • do not commit node_modules
    • run

    npm install

    grunt build
    • npm install just installs/updates modules which
    aren’t there already

    View Slide

  75. https://github.com/ddprrt/generator-netural
    http://assemble.io/
    http://fettblog.eu/blog/2013/09/02/using-assemble-io-with-
    yeoman-ios-webapp-gruntfile/

    View Slide

  76. gruntplugins

    View Slide

  77. • Install grunt-init with npm install -g grunt-init
    • Install the gruntplugin template with git clone
    git://github.com/gruntjs/grunt-init-
    gruntplugin.git ~/.grunt-init/gruntplugin
    • Run grunt-init gruntplugin in an empty directory.!
    • Run npm install to prepare the development
    environment.

    View Slide

  78. View Slide

  79. View Slide

  80. View Slide

  81. grunt++

    View Slide

  82. 'use strict';
    !
    module.exports = function(grunt) {
    // load all grunt tasks
    require('load-grunt-tasks')(grunt);
    !
    ...
    !
    };
    npm install --save-dev load-grunt-tasks

    View Slide

  83. 'use strict';
    !
    module.exports = function(grunt) {
    require(‘matchdep’)
    .filterDev(‘grunt-*')
    .forEach(grunt.loadNpmTasks); // faster!
    !
    ...
    };
    npm install --save-dev matchdep

    View Slide

  84. 'use strict';
    !
    module.exports = function(grunt) {
    require(‘load-grunt-config')(grunt);
    !
    //Config intialized … now registerTasks
    ...
    };
    npm install --save-dev load-grunt-config

    View Slide

  85. - myproject/
    |-- Gruntfile.js
    |-- grunt/
    |-- concat.js
    |-- uglify.js
    |-- imagemin.js

    View Slide

  86. // uglify.js
    !
    module.exports = {
    dist: {
    files: {
    'dist/build.min.js': ['dist/build.js']
    }
    }
    };

    View Slide

  87. http://use-init.com/
    http://www.html5rocks.com/en/tutorials/tooling/
    supercharging-your-gruntfile/

    View Slide

  88. // grunt-contrib-concurrent runs tasks parallel
    !
    concurrent: {
    dist: [
    'sass',
    'assemble'
    ],
    }

    View Slide

  89. View Slide

  90. • Stream based build system
    • Configuration over code
    • Simple API
    • Small idiomatic Node modules
    Gulp?

    View Slide

  91. • Accessing the file system too often
    • Not really a “pipe” — tasks are run sequentially
    without being connected to the other
    With Grunt …

    View Slide

  92. • The Pipe is everything
    • Defining one bigger “task” of smaller build steps
    With Gulp …

    View Slide

  93. Gulp API
    gulp.task(‘taskname’, [‘deps’], fn);
    gulp.watch(‘files.js’, [‘tasks’], fn);
    gulp.src([’files.js’]);
    gulp.dest(’endpoint.js’);

    View Slide

  94. View Slide

  95. View Slide

  96. Apples & Oranges
    • Code over configuration
    • Tasks run a sequence of
    methods
    • Methods don’t care
    about IO
    • Good amount of plugins,
    able to use unrelated
    modules
    • Configuration over code
    • Small, independent
    tasks, but with strong
    connection to IO
    • S**tload of plugins, a lot
    of them not really good
    • There might be a task for
    your need already there

    View Slide

  97. View Slide

  98. View Slide

  99. node-task
    • https://github.com/node-task/spec
    • Common ground for both gulp and grunt
    • Uses best practices of both libraries
    • The only thing different will be the interface

    View Slide

  100. yeoman

    View Slide

  101. • yeoman takes care about project scaffolding: installing
    best practices and common project standards by just one
    click!
    • plenty of official and community generators are out there!
    • overcomes blank page angst

    View Slide

  102. npm install -g yo
    npm install -g generator-webapp
    yo webapp
    this.template()
    Usage

    View Slide

  103. this.prompt()
    this.mkdir()
    this.copy()
    this.template()
    API

    View Slide

  104. workingdraft.de/159

    View Slide

  105. workingdraft.de/152

    View Slide

  106. workingdraft.de/78

    View Slide

  107. View Slide

  108. View Slide