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
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
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
26
The 4-Slide Deck
zastrow
0
22
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
15年続くIoTサービスのSREエンジニアが挑む分散トレーシング導入
melonps
2
190
humanlayerのブログから学ぶ、良いCLAUDE.mdの書き方
tsukamoto1783
0
190
KIKI_MBSD Cybersecurity Challenges 2025
ikema
0
1.3k
Fluid Templating in TYPO3 14
s2b
0
130
Architectural Extensions
denyspoltorak
0
280
SourceGeneratorのススメ
htkym
0
190
今こそ知るべき耐量子計算機暗号(PQC)入門 / PQC: What You Need to Know Now
mackey0225
3
370
メルカリのリーダビリティチームが取り組む、AI時代のスケーラブルな品質文化
cloverrose
2
510
「ブロックテーマでは再現できない」は本当か?
inc2734
0
930
なぜSQLはAIぽく見えるのか/why does SQL look AI like
florets1
0
450
プロダクトオーナーから見たSOC2 _SOC2ゆるミートアップ#2
kekekenta
0
200
ぼくの開発環境2026
yuzneri
0
190
Featured
See All Featured
brightonSEO & MeasureFest 2025 - Christian Goodrich - Winning strategies for Black Friday CRO & PPC
cargoodrich
3
98
Why Mistakes Are the Best Teachers: Turning Failure into a Pathway for Growth
auna
0
51
My Coaching Mixtape
mlcsv
0
47
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
110
How to Get Subject Matter Experts Bought In and Actively Contributing to SEO & PR Initiatives.
livdayseo
0
64
How Software Deployment tools have changed in the past 20 years
geshan
0
32k
Site-Speed That Sticks
csswizardry
13
1.1k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
287
14k
YesSQL, Process and Tooling at Scale
rocio
174
15k
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
49
9.9k
How to Ace a Technical Interview
jacobian
281
24k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.1k
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]