$30 off During Our Annual Pro Sale. View Details »

Automated Front-end Development with Grunt

FEVR
October 27, 2014

Automated Front-end Development with Grunt

Preprocessors, minification, image enhancement, and then testing, deployment .. How many tasks we do every day? And how many different tools we have to use along our workflow?
Marco Solazzi gives us the solution, strictly javascript based, called Gruntjs

FEVR

October 27, 2014
Tweet

More Decks by FEVR

Other Decks in Programming

Transcript

  1. Automated
    Front-end
    Development
    with Grunt

    View Slide

  2. About me
    ▪Senior Front-end Developer @ Intesys
    ▪Articolista JavaScript @ HTML.it
    ▪Co-founder Frontenders Verona

    View Slide

  3. About me
    ▪Senior Front-end Developer @ AQuést
    ▪Articolista JavaScript @ HTML.it
    ▪Co-founder Frontenders Verona

    View Slide

  4. ▪Ottimizzare il workflow
    ▪Ottimizzare il codice
    Front-end automation

    View Slide

  5. Ottimizzare il workflow

    View Slide

  6. Back in the ‘90...

    View Slide

  7. Not just HTML & CSS

    View Slide

  8. Not just HTML & CSS

    View Slide

  9. View Slide

  10. Ottimizzare il codice

    View Slide

  11. Performance Golden Rule:
    “80-90% of the end-user response
    time is spent on the frontend.”
    - Steve Souders
    (http://www.stevesouders.com/blog/2012/02/10/the-performance-golden-rule/)

    View Slide

  12. http://www.stevesouders.com/blog/2012/02/10/the-performance-golden-rule/
    TOP 10 Alexa websites Febbraio 2012

    View Slide

  13. “Users expect pages to load in two seconds
    — and after three seconds,
    up to 40 percent will simply leave.”
    - Lara Hogan
    (http://alistapart.com/article/improving-ux-through-front-end-performance)

    View Slide

  14. Performance tips
    ▪Ridurre le richieste HTTP
    ▪Minificare JavaScript e CSS e comprimerli (gzip)
    ▪Ottimizzare le immagini
    ▪Resource hashing + Expires o Cache-Control Header
    ▪Utilizzare sprite
    https://developers.google.com/speed/docs/best-practices/rules_intro

    View Slide

  15. Do it by hand?!?!

    View Slide

  16. View Slide

  17. Tools
    matter

    View Slide

  18. If your "build process" is the F5 key,
    you have a problem.
    - Jeff Atwood
    (http://www.codinghorror.com/blog/2007/10/the-f5-key-is-not-a-build-process.html)

    View Slide

  19. Some fair options

    View Slide

  20. Front-end friendly?

    View Slide

  21. Grunt
    to the
    rescue!

    View Slide

  22. Grunt cosa?
    ▪JavaScript based task runner
    ▪Creato da Ben Alman nel 2012
    ▪49 Contributors
    ▪8500+ stars su GitHub

    View Slide

  23. Vantaggi
    ▪Scritto in Nodejs
    ▪Installabile come modulo npm
    ▪Configurazione in formato JSON
    ▪Estendibile con moduli JavaScript
    ▪3500+ plugins (http://gruntjs.com/plugins)

    View Slide

  24. Built with Grunt...
    ▪Adobe Brackets
    ▪jQuery
    ▪Tweetdeck
    ▪Bootstrap
    ▪Modernizr
    ▪Opera GitHub Projects
    ▪WordPress Build Process
    ▪Ghost

    View Slide

  25. Getting
    started...

    View Slide

  26. npm install --save-dev grunt-contrib-concat grunt-contrib-uglifyjs
    # concatenazione di file e minificazione js con uglifyjs
    Configurazione di base
    sudo npm install -g grunt-cli # -g installa globalmente
    1) Installazione runtime
    cd grunt-demo
    npm init
    # reply to prompts...
    2) Creazione file di progetto package.json
    npm install --save-dev grunt # --save-dev salva un riferimento alla libreria in package.json
    3) Installazione delle librerie di base di grunt
    4) Installazione plugins

    View Slide

  27. package.json
    {
    "name": "grunt-demo",
    "version": "0.0.1",
    ...
    "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-concat": "~0.5.0",
    "grunt-contrib-uglify": "~0.6.0"
    }
    }

    View Slide

  28. Struttura della cartelle

    View Slide

  29. Struttura della cartelle
    Edit Here

    View Slide

  30. Struttura della cartelle
    Edit Here
    Build Here

    View Slide

  31. Struttura della cartelle
    Build File!

    View Slide

  32. Gruntfile.js
    Il Gruntfile è il file in cui vengono caricati e
    configurati i task installati

    View Slide

  33. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };

    View Slide

  34. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);};
    legge package.json e lo salva
    per gli altri task

    View Slide

  35. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };
    legge i file JS e li concatena

    View Slide

  36. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };
    minifica i sorgenti

    View Slide

  37. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };
    commento generato dinamicamente

    View Slide

  38. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };
    riferimenti ad altri task

    View Slide

  39. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };
    carica i plugin/task installati

    View Slide

  40. module.exports = function(grunt) {
    grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
    dist: {
    src: ['src/javascripts/base.js', 'src/javascripts/modules.js', 'src/javascripts/application.js'],
    dest: 'dist/javascripts/application.js'
    }
    },
    uglify: {
    options: {
    banner: '/*! <%= pkg.name %> <%= grunt.template.today("dd-mm-yyyy") %> */\n'
    },
    dist: {
    files: {
    'dist/javascripts/application.min.js': ['<%= concat.dist.dest %>']
    }
    }
    }
    });
    ['grunt-contrib-uglify', 'grunt-contrib-concat'].forEach(grunt.loadNpmTasks);
    grunt.registerTask('default', ['concat', 'uglify']);
    };
    definisce un task di default

    View Slide

  41. Output del comando

    View Slide

  42. aLL THE tHINGS!
    G R U N T I F Y

    View Slide

  43. WOK
    https://github.com/intesys/wok
    “tasty website cookware”

    View Slide

  44. WOK is a loosely opinionated boilerplate for web
    development built with flexibility and productivity
    in mind.

    View Slide

  45. Ingredienti...
    ▪Sass + Compass ( + Bootstrap-Sass)
    ▪Ottimizzazione e minificazione CSS, JS e immagini
    ▪EJS Templating (Jade coming soon...)
    ▪Markdown partials, JSON data & fixtures
    ▪Environment specific code blocks
    ▪Asset filename revving
    ▪Analisi e build custom di Modernizr
    ▪Sass automated styleguide
    ▪Server statico locale + watch + live reload / Browsersync
    ▪Deploy remoto con rsync
    ▪Server weinre per debug mobile

    View Slide

  46. demo time...

    View Slide

  47. Thank you!
    @dwightjack
    https://github.com/dwightjack

    View Slide