Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Grunting Maintainability
Search
Philip Zastrow
April 02, 2014
Programming
1
390
Grunting Maintainability
Overview of using the Grunt JS task runner and working with some useful Grunt Plugins.
Philip Zastrow
April 02, 2014
Tweet
Share
More Decks by Philip Zastrow
See All by Philip Zastrow
The One Slide Deck
zastrow
0
18
The 4-Slide Deck
zastrow
0
19
Mixin It Up
zastrow
1
88
Designing Responsively from Mobile to HD
zastrow
6
290
Pushing Pixels to Cranking Code
zastrow
3
1.9k
Other Decks in Programming
See All in Programming
Patterns of Patterns
denyspoltorak
0
370
C-Shared Buildで突破するAI Agent バックテストの壁
po3rin
0
420
Cap'n Webについて
yusukebe
0
150
AtCoder Conference 2025
shindannin
0
710
【卒業研究】会話ログ分析によるユーザーごとの関心に応じた話題提案手法
momok47
0
130
Vibe codingでおすすめの言語と開発手法
uyuki234
0
130
Grafana:建立系統全知視角的捷徑
blueswen
0
240
Jetpack XR SDKから紐解くAndroid XR開発と技術選定のヒント / about-androidxr-and-jetpack-xr-sdk
drumath2237
1
190
Kotlin Multiplatform Meetup - Compose Multiplatform 외부 의존성 아키텍처 설계부터 운영까지
wisemuji
0
130
開発に寄りそう自動テストの実現
goyoki
2
1.5k
Pythonではじめるオープンデータ分析〜書籍の紹介と書籍で紹介しきれなかった事例の紹介〜
welliving
3
630
愛される翻訳の秘訣
kishikawakatsumi
3
350
Featured
See All Featured
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.1k
Pawsitive SEO: Lessons from My Dog (and Many Mistakes) on Thriving as a Consultant in the Age of AI
davidcarrasco
0
38
Paper Plane (Part 1)
katiecoart
PRO
0
2.2k
The Mindset for Success: Future Career Progression
greggifford
PRO
0
200
Accessibility Awareness
sabderemane
0
24
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
34
2.6k
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.5k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.2k
Context Engineering - Making Every Token Count
addyosmani
9
560
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
286
14k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
10
760
Transcript
Philip Zastrow GRUNTING MAINTAINABILITY @zastrow
ROBOTS A CHILDHOOD MEMORY OF
THERE WAS A ROBOT AT MY GRAMPA’S WORKPLACE
THE ARM HELPED MAKE COMPUTER PROCESSORS
MY GRAMPA DIDN’T DESIGN THE ROBOT
None
HIS PART TURNED MANY SMALL FUNCTIONS INTO A ROBOT
GRUNTING MAINTAINABILITY FRONTEND TOOLS
HTML CSS JS WHAT WE BUILD
HBS SCSS COFFEE HOW WE BUILD
sass input.scss output.css sass watch SCSS CSS
coffee --compile coffee --watch COFFEE JS
ONE COMMAND ONE FUNCTION
WE NEED A FRONTEND ROBOT
None
None
grunt grunt watch COFFEE JS SCSS CSS
ONE COMMAND MANY FUNCTIONS
WHAT IS GRUNT?
Grunt is a tool that binds your other tools together
GRUNT IS A TASK RUNNER
THERE IS A BUFFET OF TASK RUNNERS
HELPS AUTOMATE TEDIOUS WORK GRUNT IS A TASK RUNNER
GRUNT AUTOMATES RUNNING TESTS
GRUNT AUTOMATES RUNNING TESTS FILE CONVERSION
GRUNT AUTOMATES RUNNING TESTS FILE CONVERSION CONCATENATION
nodejs.org brew install node
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
HOW DOES GRUNT WORK?
gruntjs.com/getting-started npm install -g grunt-cli GRUNT CLI
grunt
package.json Node devDependencies i.e. plugins
{ "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" } }
npm install
npm install grunt-plugin --save-dev
.js or .coffee GRUNTFILE The list of instructions for each
plugin
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
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
24ways.org/2013/grunt-is-not-weird-and-hard gruntjs.com
GRUNTING MAINTAINABILITY BUILDING MAINTAINABLE WEBSITES WITH GRUNT
FRONTEND DEVELOPMENT AND HOW WE BUILD SITES
Focus primarily on HTML, CSS, and JS; Not a CMS
Any one teammate could jump on any project at anytime
Grunt helps us collaborate with each other and client dev
teams
We use Grunt on our own website seesparkbox.com
We like improving workflow, so all tools are eligible for
replacement
We like improving workflow, so all tools are eligible for
replacement …including Grunt
Frontend projects start with a Grunt scaffolding
Grunt Project coffee data dist features grunt public Gemfile Gruntfile
config.rb package.json .gitignore bower.json .bowerrc sass specs templates
Grunt Project coffee data dist features grunt public Gemfile Gruntfile
config.rb package.json .gitignore bower.json .bowerrc sass specs templates
Grunt Project coffee data dist public sass templates
GRUNT PLUGINS SPARKBOX USES
Grunt plugins are Grunt-wrapped preprocessors
Grunt Project coffee data dist public sass templates ASSEMBLE HTML
npm install assemble --save-dev assemble.io
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'
HANDLEBARS HTML STRUCTURE handlebarsjs.com
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'
Grunt Project coffee data dist public sass templates
templates layouts pages partials
templates layouts pages partials layoutdir: "templates/layouts/"
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'
layout default.hbs contact.hbs layout: ['default.hbs']
<!doctype html> <html> <head> <title> Sample Site </title> <head> <body>
{{> _site--header }} {{> body }} {{> _site--footer }} </body> </html>
<!doctype html> <html> <head> <title> Sample Site </title> <head> <body>
{{> _site--header }} {{> body }} {{! Loads in Page Content }} {{> _site--footer }} </body> </html>
<!doctype html> <html> <head> <title> Sample Site </title> <head> <body>
{{> _site--header }} {{! Loads Site Header Partial }} {{> body }} {{> _site--footer }} {{! Loads Site Footer Partial }} </body> </html>
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'
templates layout pages partials cwd: 'templates/pages'
pages index.hbs about.hbs contact.hbs
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'
index.hbs about.hbs contact.hbs cwd: 'templates/pages' src: ['*.hbs'] dest: './dist/' index.html
about.html contact.html
<div class="main_content"> <article class="main_content--article"> <header class="main_content--header"> <h1 class="main_content--title">Our Homepage</h1> <header>
<div class="article_content"> <p>This is the main content for our page.</p> </div> </article> </div> ! {{> _site--aside }}
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'
templates layout pages partials partials: "templates/partials/*"
partials _site--aside.hbs _site--footer.hbs _site--header.hbs _site--navigation.hbs
<header class="site_header"> <h1 class="site_header--title">Sample Site</h1> {{> _site--navigation }} <header>
<nav class="site_nav"> <ul class="site_nav--list"> {{#each site-nav.nav-list}} <li class="site_nav--item"> <a href=“{{target}}"
class="site_nav--link"> {{nav_item}} </a> </li> {{/each}} </ul> <nav>
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'
YAML HTML CONTENT yaml.org
YAML YAML Ain’t Markup Language yaml.org
Grunt Project coffee data dist public sass templates data: "data/*.yml"
data index.yml about.yml site-info.yml site-nav.yml
nav-list: - nav_item: Home target: "/" - nav_item: About target:
"about.html" - nav_item: Blog target: "blog.html" - nav_item: Contact target: "contact.html"
<nav class="site_nav"> <ul class="site_nav--list"> {{#each site-nav.nav-list}} <li class="site_nav--list"> <a href=“{{target}}"
class="site_nav--list"> {{nav_item}} </a> </li> {{/each}} </ul> <nav>
<nav class="site_nav"> <ul class="site_nav--list"> <li class="site_nav--list"> <a href="/" class="site_nav--list"> Home
</a> </li> <li class="site_nav--list"> <a href="about.html" class="site_nav--list"> About </a> </li> <li class="site_nav--list"> <a href="blog.html" class="site_nav--list"> Blog </a> </li> <li class="site_nav--list"> <a href="contact.html" class="site_nav--list"> {{nav_item}} </a>
<!doctype html> <html> <head> <title> Sample Site </title> <head> <body>
{{> _site-header }} {{> body }} {{> _site-footer }} </body> </html>
<!doctype html> <html> <head> <title> Sample Site </title> <head> <body>
{{> _site-header }} {{> body }} {{> _site-footer }} </body> </html>
<!doctype html> <html> <head> <title> Sample Site{{#if page_title}} | {{page_title}}{{/if}}
</title> <head> <body> {{> _site-header }} {{> body }} {{> _site-footer }} </body> </html>
YAML FRONT MATTER
--- page_title: About Us --- ! <div class="main_content"> <article class="main_content--article">
<header class="main_content--header"> <h1 class="main_content—title">{{page_title}}</h1> <header> <div class="article_content"> {{ about.page-content }} </div> </article> </div> ! {{> _site--aside }}
<!doctype html> <html> <head> <title> Sample Site{{#if page_title}} | {{page_title}}{{/if}}
</title> <head> <body> {{> _site-header }} {{> body }} {{> _site-footer }} </body> </html>
<!doctype html> <html> <head> <title> Sample Site | About Us
</title> <head> <body> <header class="site_header"> <h1 class="site_header--title">Sample Site</h1> <nav class="site_nav"> <ul class="site_nav--list"> <li class="site_nav--list"> <a href="/" class="site_nav—list"> Home </a> </li> <li class="site_nav--list"> <a href="about.html" class="site_nav--list"> About </a> </li> <li class="site_nav--list">
Grunt Project coffee data dist public sass templates SASS with
COMPASS CSS
npm install grunt-contrib-compass --save-dev github.com/gruntjs/grunt-contrib-compass
module.exports = (grunt) -> grunt.config "compass", dev: options: environment: "dev"
dist: options: environment: "production" grunt.loadNpmTasks "grunt-contrib-compass"
sass _general-extends.scss _general-mixins.scss _general-variables.scss _site--header.scss _site--navigation.scss mq-base.scss nomq-base.scss
Grunt Project coffee data dist public sass templates COFFEESCRIPT JAVASCRIPT
npm install grunt-contrib-coffee --save-dev github.com/gruntjs/grunt-contrib-coffee
module.exports = (grunt) -> grunt.config "coffee", compile: files: "dist/js/app.js": "coffee/app.coffee"
grunt.loadNpmTasks "grunt-contrib-coffee"
Grunt Project coffee data dist public sass templates
Grunt Project coffee data dist public sass templates
Grunt Project coffee data dist public sass templates CLEANED OUT
BEFORE THE SITE GENERATES
npm install grunt-contrib-clean --save-dev github.com/gruntjs/grunt-contrib-clean
module.exports = (grunt) -> grunt.config "clean", all: src: "dist/*" dot:
true #clean hidden files as well ! grunt.loadNpmTasks 'grunt-contrib-clean'
Grunt Project coffee data dist public sass templates STATIC FILES
NO PREPROCESSORS
npm install grunt-contrib-copy --save-dev github.com/gruntjs/grunt-contrib-copy
module.exports = (grunt) -> grunt.config "copy", main: files: [ expand:
true cwd: "public/" src: ["**"] dest: "dist/" ] ! grunt.loadNpmTasks 'grunt-contrib-copy'
Keep files short and let Grunt string them together
GRUNT PLUGIN ONE MORE THING!
Grunt Project coffee data dist public sass templates grunticon SVG
WITH PNG FALLBACK
npm install grunt-grunticon --save-dev github.com/filamentgroup/grunticon
module.exports = (grunt) -> grunt.config "grunticon", icons: files: [ expand:
true, cwd: "grunticon/src", src: ["*.svg"], dest: "dist/grunticon" ] ! grunt.loadNpmTasks "grunt-grunticon"
grunticon src
grunticon sample-logo.svg
grunticon png src grunticon.loader.txt icons.data.png.css icons.data.svg.css icons.fallback.css preview.html
.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%
.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
.icon-sample-logo { background-image: url(‘png/sample-logo.png'); background-repeat: no-repeat; }
data URI
Make sure SVG files are optimized github.com/svg/svgo
A Bit About SVG seesparkbox.com/foundry/a_bit_about_svg
GRUNTING MAINTAINABILITY REVIEW
None
GRUNT PLUGINS
ASSEMBLE HTML GENERATOR assemble.io npm install assemble --save-dev
SASS/COMPASS CSS GENERATOR github.com/gruntjs/contrib-grunt-compass npm install contrib-grunt-compass --save-dev
COFFEESCRIPT JS GENERATOR github.com/gruntjs/contrib-grunt-coffee npm install contrib-grunt-coffee --save-dev
CLEAN REMOVES ALL THE THINGS github.com/gruntjs/contrib-grunt-clean npm install contrib-grunt-clean --save-dev
COPY ADDS ALL THE THINGS github.com/gruntjs/contrib-grunt-copy npm install contrib-grunt-copy --save-dev
GRUNTICON SVG WITH PNG FALLBACK github.com/filamentgroup/grunticon npm install grunt-grunticon --save-dev
The goal is simplified and concise files
THAT’S GRUNTING MAINTAINABILITY
THANKS! @zastrow
[email protected]