Slide 1

Slide 1 text

Philip Zastrow GRUNTING MAINTAINABILITY @zastrow

Slide 2

Slide 2 text

ROBOTS A CHILDHOOD MEMORY OF

Slide 3

Slide 3 text

THERE WAS A ROBOT AT MY GRAMPA’S WORKPLACE

Slide 4

Slide 4 text

THE ARM HELPED MAKE COMPUTER PROCESSORS

Slide 5

Slide 5 text

MY GRAMPA DIDN’T DESIGN THE ROBOT

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

HIS PART TURNED MANY SMALL FUNCTIONS INTO A ROBOT

Slide 8

Slide 8 text

GRUNTING MAINTAINABILITY FRONTEND
 TOOLS

Slide 9

Slide 9 text

HTML CSS JS WHAT WE BUILD

Slide 10

Slide 10 text

HBS SCSS COFFEE HOW WE BUILD

Slide 11

Slide 11 text

sass input.scss output.css sass watch SCSS CSS

Slide 12

Slide 12 text

coffee --compile coffee --watch COFFEE JS

Slide 13

Slide 13 text

ONE COMMAND ONE FUNCTION

Slide 14

Slide 14 text

WE NEED A FRONTEND ROBOT

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

grunt grunt watch COFFEE JS SCSS CSS

Slide 18

Slide 18 text

ONE COMMAND MANY FUNCTIONS

Slide 19

Slide 19 text

WHAT IS GRUNT?

Slide 20

Slide 20 text

Grunt is a tool that
 binds your other
 tools together

Slide 21

Slide 21 text

GRUNT IS A TASK RUNNER

Slide 22

Slide 22 text

THERE IS A BUFFET OF TASK RUNNERS

Slide 23

Slide 23 text

HELPS AUTOMATE TEDIOUS WORK GRUNT IS A TASK RUNNER

Slide 24

Slide 24 text

GRUNT AUTOMATES RUNNING TESTS

Slide 25

Slide 25 text

GRUNT AUTOMATES RUNNING TESTS FILE CONVERSION

Slide 26

Slide 26 text

GRUNT AUTOMATES RUNNING TESTS FILE CONVERSION CONCATENATION

Slide 27

Slide 27 text

nodejs.org brew install node

Slide 28

Slide 28 text

Grunt for People Who Think Things Like Grunt are Weird and Hard —Chris Coyier, 24 Ways 24ways.org/2013/grunt-is-not-weird-and-hard

Slide 29

Slide 29 text

HOW DOES GRUNT WORK?

Slide 30

Slide 30 text

gruntjs.com/getting-started npm install -g grunt-cli GRUNT CLI

Slide 31

Slide 31 text

grunt

Slide 32

Slide 32 text

package.json Node devDependencies i.e. plugins

Slide 33

Slide 33 text

{ "name": “sample-site", "version": "0.1.0", "devDependencies": { "grunt": "~0.4.2", "assemble": "~0.4.13", "grunt-contrib-clean": "~0.4.0", "grunt-contrib-coffee": "~0.6.0", "grunt-contrib-compass": "~0.1.3", "grunt-contrib-copy": "~0.4.1" } }

Slide 34

Slide 34 text

npm install

Slide 35

Slide 35 text

npm install grunt-plugin --save-dev

Slide 36

Slide 36 text

.js or .coffee GRUNTFILE The list of instructions for each plugin

Slide 37

Slide 37 text

module.exports = function(grunt) { // Project configuration. grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), uglify: { options: { banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' }, build: { src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' } } }); // Load the plugin that provides the “uglify" task. grunt.loadNpmTasks('grunt-contrib-uglify'); // Default task(s). grunt.registerTask('default', ['uglify']); }; Example code from gruntjs.com

Slide 38

Slide 38 text

module.exports = (grunt) -> # Project configuration. grunt.initConfig pkg: require("package.json") uglify: options: banner: '/*! <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> */\n' build: src: 'src/<%= pkg.name %>.js', dest: 'build/<%= pkg.name %>.min.js' ! # Load the plugin that provides the “uglify" task. grunt.loadNpmTasks 'grunt-contrib-uglify' # Default task(s). grunt.registerTask 'default', ['uglify'] Example code from gruntjs.com

Slide 39

Slide 39 text

24ways.org/2013/grunt-is-not-weird-and-hard gruntjs.com

Slide 40

Slide 40 text

GRUNTING MAINTAINABILITY BUILDING MAINTAINABLE WEBSITES
 WITH GRUNT

Slide 41

Slide 41 text

FRONTEND DEVELOPMENT AND HOW WE BUILD SITES

Slide 42

Slide 42 text

Focus primarily on HTML, CSS, and JS; Not a CMS

Slide 43

Slide 43 text

Any one teammate could jump on any project at anytime

Slide 44

Slide 44 text

Grunt helps us collaborate with each other and
 client dev teams

Slide 45

Slide 45 text

We use Grunt on our own website seesparkbox.com

Slide 46

Slide 46 text

We like improving workflow, so all tools are eligible for replacement

Slide 47

Slide 47 text

We like improving workflow, so all tools are eligible for replacement …including Grunt

Slide 48

Slide 48 text

Frontend projects start with a Grunt scaffolding

Slide 49

Slide 49 text

Grunt Project coffee data dist features grunt public Gemfile Gruntfile config.rb package.json .gitignore bower.json .bowerrc sass specs templates

Slide 50

Slide 50 text

Grunt Project coffee data dist features grunt public Gemfile Gruntfile config.rb package.json .gitignore bower.json .bowerrc sass specs templates

Slide 51

Slide 51 text

Grunt Project coffee data dist public sass templates

Slide 52

Slide 52 text

GRUNT PLUGINS SPARKBOX USES

Slide 53

Slide 53 text

Grunt plugins are Grunt-wrapped preprocessors

Slide 54

Slide 54 text

Grunt Project coffee data dist public sass templates ASSEMBLE HTML

Slide 55

Slide 55 text

npm install assemble --save-dev assemble.io

Slide 56

Slide 56 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 57

Slide 57 text

HANDLEBARS HTML STRUCTURE handlebarsjs.com

Slide 58

Slide 58 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 59

Slide 59 text

Grunt Project coffee data dist public sass templates

Slide 60

Slide 60 text

templates layouts pages partials

Slide 61

Slide 61 text

templates layouts pages partials layoutdir: "templates/layouts/"

Slide 62

Slide 62 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 63

Slide 63 text

layout default.hbs contact.hbs layout: ['default.hbs']

Slide 64

Slide 64 text

Sample Site {{> _site--header }} {{> body }} {{> _site--footer }}

Slide 65

Slide 65 text

Sample Site {{> _site--header }} {{> body }} {{! Loads in Page Content }} {{> _site--footer }}

Slide 66

Slide 66 text

Sample Site {{> _site--header }} {{! Loads Site Header Partial }} {{> body }} {{> _site--footer }} {{! Loads Site Footer Partial }}

Slide 67

Slide 67 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 68

Slide 68 text

templates layout pages partials cwd: 'templates/pages'

Slide 69

Slide 69 text

pages index.hbs about.hbs contact.hbs

Slide 70

Slide 70 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 71

Slide 71 text

index.hbs about.hbs contact.hbs cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' index.html about.html contact.html

Slide 72

Slide 72 text

Our Homepage

This is the main content for our page.

! {{> _site--aside }}

Slide 73

Slide 73 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 74

Slide 74 text

templates layout pages partials partials: "templates/partials/*"

Slide 75

Slide 75 text

partials _site--aside.hbs _site--footer.hbs _site--header.hbs _site--navigation.hbs

Slide 76

Slide 76 text

Sample Site

{{> _site--navigation }}

Slide 77

Slide 77 text

Slide 78

Slide 78 text

module.exports = (grunt) -> grunt.config "assemble", options: partials: "templates/partials/*" data: "data/*.yml" layoutdir: "templates/layouts/" layout: ['default.hbs'] files: expand: true cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' ! grunt.loadNpmTasks 'assemble'

Slide 79

Slide 79 text

YAML HTML CONTENT yaml.org

Slide 80

Slide 80 text

YAML YAML Ain’t Markup Language yaml.org

Slide 81

Slide 81 text

Grunt Project coffee data dist public sass templates data: "data/*.yml"

Slide 82

Slide 82 text

data index.yml about.yml site-info.yml site-nav.yml

Slide 83

Slide 83 text

nav-list: - nav_item: Home target: "/" - nav_item: About target: "about.html" - nav_item: Blog target: "blog.html" - nav_item: Contact target: "contact.html"

Slide 84

Slide 84 text

Slide 86

Slide 86 text

Sample Site {{> _site-header }} {{> body }} {{> _site-footer }}

Slide 87

Slide 87 text

Sample Site {{> _site-header }} {{> body }} {{> _site-footer }}

Slide 88

Slide 88 text

Sample Site{{#if page_title}} | {{page_title}}{{/if}} {{> _site-header }} {{> body }} {{> _site-footer }}

Slide 89

Slide 89 text

YAML FRONT MATTER

Slide 90

Slide 90 text

--- page_title: About Us --- !

{{page_title}}

{{ about.page-content }}
! {{> _site--aside }}

Slide 91

Slide 91 text

Sample Site{{#if page_title}} | {{page_title}}{{/if}} {{> _site-header }} {{> body }} {{> _site-footer }}

Slide 92

Slide 92 text

Sample Site | About Us

Sample Site

Slide 93

Slide 93 text

Grunt Project coffee data dist public sass templates SASS with COMPASS CSS

Slide 94

Slide 94 text

npm install grunt-contrib-compass --save-dev github.com/gruntjs/grunt-contrib-compass

Slide 95

Slide 95 text

module.exports = (grunt) -> grunt.config "compass", dev: options: environment: "dev" dist: options: environment: "production" grunt.loadNpmTasks "grunt-contrib-compass"

Slide 96

Slide 96 text

sass _general-extends.scss _general-mixins.scss _general-variables.scss _site--header.scss _site--navigation.scss mq-base.scss nomq-base.scss

Slide 97

Slide 97 text

Grunt Project coffee data dist public sass templates COFFEESCRIPT JAVASCRIPT

Slide 98

Slide 98 text

npm install grunt-contrib-coffee --save-dev github.com/gruntjs/grunt-contrib-coffee

Slide 99

Slide 99 text

module.exports = (grunt) -> grunt.config "coffee", compile: files: "dist/js/app.js": "coffee/app.coffee" grunt.loadNpmTasks "grunt-contrib-coffee"

Slide 100

Slide 100 text

Grunt Project coffee data dist public sass templates

Slide 101

Slide 101 text

Grunt Project coffee data dist public sass templates

Slide 102

Slide 102 text

Grunt Project coffee data dist public sass templates CLEANED OUT BEFORE THE SITE GENERATES

Slide 103

Slide 103 text

npm install grunt-contrib-clean --save-dev github.com/gruntjs/grunt-contrib-clean

Slide 104

Slide 104 text

module.exports = (grunt) -> grunt.config "clean", all: src: "dist/*" dot: true #clean hidden files as well ! grunt.loadNpmTasks 'grunt-contrib-clean'

Slide 105

Slide 105 text

Grunt Project coffee data dist public sass templates STATIC FILES NO PREPROCESSORS

Slide 106

Slide 106 text

npm install grunt-contrib-copy --save-dev github.com/gruntjs/grunt-contrib-copy

Slide 107

Slide 107 text

module.exports = (grunt) -> grunt.config "copy", main: files: [ expand: true cwd: "public/" src: ["**"] dest: "dist/" ] ! grunt.loadNpmTasks 'grunt-contrib-copy'

Slide 108

Slide 108 text

Keep files short and let Grunt string them together

Slide 109

Slide 109 text

GRUNT PLUGIN ONE MORE THING!

Slide 110

Slide 110 text

Grunt Project coffee data dist public sass templates grunticon SVG WITH PNG FALLBACK

Slide 111

Slide 111 text

npm install grunt-grunticon --save-dev github.com/filamentgroup/grunticon

Slide 112

Slide 112 text

module.exports = (grunt) -> grunt.config "grunticon", icons: files: [ expand: true, cwd: "grunticon/src", src: ["*.svg"], dest: "dist/grunticon" ] ! grunt.loadNpmTasks "grunt-grunticon"

Slide 113

Slide 113 text

grunticon src

Slide 114

Slide 114 text

grunticon sample-logo.svg

Slide 115

Slide 115 text

grunticon png src grunticon.loader.txt icons.data.png.css icons.data.svg.css icons.fallback.css preview.html

Slide 116

Slide 116 text

.icon-sample-logo { background-image: url(‘data:image/svg +xml;charset=US-ASCII,%3C%3Fxml %20version%3D %221.0%22%20encoding%3D %22UTF-8%22%20standalone%3D%22no%22%3F%3E%3Csvg %20width%3D%22302px%22%20height%3D%2266px %22%20viewBox%3D%220%200%20302%2066%22%20version%3D %221.1%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org %2F2000%2Fsvg%22%20xmlns%3Axlink%3D%22http%3A%2F %2Fwww.w3.org%2F1999%2Fxlink%22%3E %20%20%20%20%3Ctitle%3EButton%3C%2Ftitle%3E %20%20%20%20%3Cdefs%3E%20%20%20%20%20%20%3Cstyle%3E %20%20%20%20%20%20%20%20.button--path%20%7B %20%20%20%20%20%20%20%20%20%20fill%3A%20%23D4D4D4%3B %20%20%20%20%20%20%20%20%7D%20%20%20%20%20%20%3C %2Fstyle%3E%20%20%20%20%3C%2Fdefs%3E %20%20%20%20%3Cpath%20class%3D%22button--path%22%20d %3D
 %22M244.681203%2C0%20L56.2445924%2C0%20C27.7845831%2C 0%200%2C33.8953123%200%2C33.8953123%20C0%2C33.8953123 %2026.3926138%2C65.9999996%2055.4422152%2C65.9999996% 20C137.527029%2C65.9999996%20218.318013%2C66.0000005%

Slide 117

Slide 117 text

.icon-sample-logo { background-image: url(‘data:image/ png;base64,iVBORw0KGgoAAAANSUhEUgAAAS4AAABCCAYAAADpAT vWAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEwAACxMBAJqcGAA ACGpJREFUeJzt3XuMXGUZBvDn/Wa6uy5toS0bE2OUEly3O +eMVrZaFdRN1CbEpqYNBaHBGAtyCaigTRo0AaoxBIsXEoLIRZRU2F CQgEgpcYlJCZcRh3POzGxWCAIBQlgSUzRMpzPv6x/ uku2ys7tzPbPd5/ff5sx5v2f/ eXL22znnCBa5IAhOBTDknDvdzNYCWG1mawCsBrDaObc83oRE7aWqJ efcuwAOq+rrzrnXALxgZhGAoFAoRNu3b6/ EHLMhEneAWgVBkHbOfR3A51X1dOfcmrgzES0mqvqOc+4pAKNm9ojv +8/ HnalWi6K4oij6NIBtqrrVOXda3HmIjjOvArgfwD7P856JO8xCdGxx BUGwSkQuBHCJiJwScxyiJUFV/ ykiv122bNmdAwMDE3HnqabjiiuXy6VU9QoR2QGgN +48REvR5D7ZPaq6N51OB3HnmaljiiuXy33GzK4D8NW4sxDRMQ6Y2R 7f9w/ FHWRK7MU1eYX1UxHZEncWIqrOzB53zv0olUo9HXeW2IqrUCicUqlU rlPV851zLq4cRFQbVb3PObfb87wX4srQ9uKKoqjLzHaZ2dXOuZ52r 09EjZvcA/ slgD2e5/2n3eu3tbjCMBwWkZsBDLRzXSJqDVV9HcD30+n0SDvXbUt

Slide 118

Slide 118 text

.icon-sample-logo { background-image: url(‘png/sample-logo.png'); background-repeat: no-repeat; }

Slide 119

Slide 119 text

data URI

Slide 120

Slide 120 text

Make sure SVG files are optimized github.com/svg/svgo

Slide 121

Slide 121 text

A Bit About SVG seesparkbox.com/foundry/a_bit_about_svg

Slide 122

Slide 122 text

GRUNTING MAINTAINABILITY REVIEW

Slide 123

Slide 123 text

No content

Slide 124

Slide 124 text

GRUNT PLUGINS

Slide 125

Slide 125 text

ASSEMBLE HTML GENERATOR assemble.io npm install assemble --save-dev

Slide 126

Slide 126 text

SASS/COMPASS CSS GENERATOR github.com/gruntjs/contrib-grunt-compass npm install contrib-grunt-compass --save-dev

Slide 127

Slide 127 text

COFFEESCRIPT JS GENERATOR github.com/gruntjs/contrib-grunt-coffee npm install contrib-grunt-coffee --save-dev

Slide 128

Slide 128 text

CLEAN REMOVES ALL THE THINGS github.com/gruntjs/contrib-grunt-clean npm install contrib-grunt-clean --save-dev

Slide 129

Slide 129 text

COPY ADDS ALL THE THINGS github.com/gruntjs/contrib-grunt-copy npm install contrib-grunt-copy --save-dev

Slide 130

Slide 130 text

GRUNTICON SVG WITH PNG FALLBACK github.com/filamentgroup/grunticon npm install grunt-grunticon --save-dev

Slide 131

Slide 131 text

The goal is simplified and concise files

Slide 132

Slide 132 text

THAT’S GRUNTING MAINTAINABILITY

Slide 133

Slide 133 text

THANKS! @zastrow [email protected]