Slide 1

Slide 1 text

Automated Front-end Development with Grunt

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

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

Slide 5

Slide 5 text

Ottimizzare il workflow

Slide 6

Slide 6 text

Back in the ‘90...

Slide 7

Slide 7 text

Not just HTML & CSS

Slide 8

Slide 8 text

Not just HTML & CSS

Slide 9

Slide 9 text

No content

Slide 10

Slide 10 text

Ottimizzare il codice

Slide 11

Slide 11 text

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/)

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

“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)

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

Do it by hand?!?!

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Tools matter

Slide 18

Slide 18 text

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)

Slide 19

Slide 19 text

Some fair options

Slide 20

Slide 20 text

Front-end friendly?

Slide 21

Slide 21 text

Grunt to the rescue!

Slide 22

Slide 22 text

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

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

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

Slide 25

Slide 25 text

Getting started...

Slide 26

Slide 26 text

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

Slide 27

Slide 27 text

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

Slide 28

Slide 28 text

Struttura della cartelle

Slide 29

Slide 29 text

Struttura della cartelle Edit Here

Slide 30

Slide 30 text

Struttura della cartelle Edit Here Build Here

Slide 31

Slide 31 text

Struttura della cartelle Build File!

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

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

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

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

Slide 38

Slide 38 text

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

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

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

Slide 41

Slide 41 text

Output del comando

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

demo time...

Slide 47

Slide 47 text

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