Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Assets Build Automation
Search
Marconi Moreto
February 25, 2014
Programming
320
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Assets Build Automation
Automated building of your webapp assets using Gruntjs.
Marconi Moreto
February 25, 2014
More Decks by Marconi Moreto
See All by Marconi Moreto
Development Mini Toolbox
marconi
1
190
Introduction to Docker
marconi
4
1.3k
SaltStack 101
marconi
10
1.1k
Concurrency with Gevent
marconi
3
430
Django Quickstart
marconi
1
140
Other Decks in Programming
See All in Programming
App Storeの外へ──日本のiOSサイドローディング入門 for iOSDC Japan 2026
yuukiw00w
0
170
Security issues being discussed on Web Platforms
petamoriken
0
700
The Past, Present, and Future of Enterprise Java
ivargrimstad
0
220
Heart of Swift Concurrency
koher
0
190
個人開発基盤をまるごとCloudflareに引っ越して爆速で総合的体験を向上させた話
tinykitten
0
160
Laravelのアプリケーションをどこにデプロイするか #ツナギメオフライン.9
akase244
0
120
AI × TiDD / 2026.09.05 Redmine 大阪
tokudiro
1
120
『寄り添うラジオ』をAIで作る 体験価値から逆算した、会話しないUXと品質設計
theoriatec2024
3
150
Swift愛好会100回記念 第1回を振り返る
jollyjoester
0
120
XP祭りでしか伝わらないフリップネタ #xpjug
murabayashi
0
130
新人はどこまで自力でやり、どこからAIに頼るべきか/エンジニア育成に向き合う_先輩たちの悩みと知見共有会
toppan_digital_dev
1
600
Can LLMs Replicate 4 Years of Compose Migration? Exploring the boundaries of automation with 279 XML files from a real product
makun
0
130
Featured
See All Featured
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
141
35k
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
WENDY [Excerpt]
tessaabrams
13
39k
The Anti-SEO Checklist Checklist. Pubcon Cyber Week
ryanjones
0
230
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
25
2.1k
Large-scale JavaScript Application Architecture
addyosmani
515
110k
Lessons Learnt from Crawling 1000+ Websites
charlesmeaden
PRO
1
1.6k
Speed Design
sergeychernyshev
33
2.1k
The Curious Case for Waylosing
cassininazir
1
500
Building an army of robots
kneath
306
46k
The SEO identity crisis: Don't let AI make you average
varn
0
550
The World Runs on Bad Software
bkeepers
PRO
72
12k
Transcript
Assets Build Automation Marconi Moreto @marconimjr
Story time...
Classic way: <!doctype html> <html> <head> <title>My Awesome WebApp</title> <link
href="/static/css/somegrid.css" type="text/css" rel="stylesheet"/> <link href="/static/css/plugins.css" type="text/css" rel="stylesheet"/> <link href="/static/css/styles.css" type="text/css" rel="stylesheet"/> </head> <body> ... <script src="/static/js/jquery.js" type="text/javascript"></script> <script src="/static/js/plugins.js" type="text/javascript"></script> <script src="/static/js/app.js" type="text/javascript"></script> </body> </html> Number of requests: 7
None
Concatenate everything: <!doctype html> <html> <head> <title>My Awesome WebApp</title> <link
href="/static/css/app.css" type="text/css" rel="stylesheet"/> </head> <body> ... <script src="/static/js/app.js" type="text/javascript"></script> </body> </html> Number of requests: 3
Quick peak 1/2 body { padding: 0; margin: 0; }
#notification { width: 100%; font-size: 18px; text-align: center; padding: 15px 0; } #notification.success { background: #1abc9c; } #notification.error { background: #e74c3c; } app.css app.js /** * Basic notification class */ function Notification(msg, type) { this.msg = msg; this.type = typeof type !== 'undefined' ? type : 'success'; } Notification.prototype.show = function() { // build notification var notif = document.createElement('div'); notif.id = 'notification'; notif.className = this.type; notif.innerHTML = this.msg; // prepend notificaiton var doc = document.getElementsByTagName("body")[0]; doc.insertBefore(notif, doc.firstChild); }; $(function() { new Notification("Welcome!").show(); })(); Size: 277 bytes Size: 543 bytes
None
Minify everything: <!doctype html> <html> <head> <title>My Awesome WebApp</title> <link
href="/static/css/app.min.css" type="text/css" rel="stylesheet"/> </head> <body> ... <script src="/static/js/app.min.js" type="text/javascript"></script> </body> </html> ✓ Number of requests: 3 ✓ Faster loading time
Quick peak 2/2 body{padding:0;margin:0} #notification{width: 100%;font-size:18px;text- align:center;padding:15px 0} #notification.success{backg round:#1abc9c}
#notification.error{backgro und:#e74c3c} app.min.css app.min.js function Notification(a,b){this.msg=a,this.type="undefined"! =typeof b?b:"success"}Notification.prototype.show=function() {var a=document.createElement("div");a.id="notification",a.classNam e=this.type,a.innerHTML=this.msg;var b=document.getElementsByTagName("body") [0];b.insertBefore(a,b.firstChild)},$(function(){new Notification("Welcome!").show()})(); Size: 277 bytes Size: 177 bytes Size: 543 bytes Size: 352 bytes
None
Why do all these?
None
None
None
But why do we automate?
None
But really, why do we automate?
Focus on fun stuff!
The JavaScript Task Runner
✓ Node ✓ JS/Coffee + JSON ✓ Focus on web
development ✓ Over 2,294 plugins! Things to love about Grunt:
None
Who’s using it? And some more: Wordpress, Opera, etc.
$ npm install -g grunt-cli - package.json - Gruntfile.(js|coffee) Getting
started: Installation: Requirements:
{ "name": "MyAwesomeApp", "version": "0.0.1", "private": true } package.json $
npm install grunt --save $ npm install grunt-contrib-uglify --save $ npm install grunt-contrib-cssmin --save ... $ cat package.json { "name": "MyAwesomeApp", "version": "0.0.1", "private": true, "dependencies": { "grunt": "~0.4.2", "grunt-contrib-uglify": "~0.3.2", "grunt-contrib-cssmin": "~0.8.0" } } Install dependencies:
CSS Minification
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), cssmin: { styles:
{ files: { 'static/css/app.min.css': ['src/css/*.css'] } } } }); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.registerTask('default', ['cssmin']); }; Gruntfile.js Lets run it! $ grunt
JS Minification
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), cssmin: { styles:
{ files: { 'static/css/app.min.css': ['src/css/*.css'] } } }, uglify: { scripts: { files: { 'static/js/app.min.js': [ 'src/js/jquery.js', 'src/js/plugins.js', 'src/js/app.js' ] } } } }); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['cssmin']); grunt.registerTask('deploy', ['cssmin', 'uglify']); }; Gruntfile.js: Lets run it! $ grunt deploy
Concatenate on development + minify on deploy
module.exports = function(grunt) { grunt.initConfig({ ... concat: { dist: {
src: ['src/js/**/*.js'], dest: 'static/js/app.all.js' } }, uglify: { scripts: { files: { 'static/js/app.min.js': ['static/js/app.all.js'] } } } }); ... grunt.loadNpmTasks('grunt-contrib-concat'); grunt.registerTask('default', ['cssmin', 'concat']); grunt.registerTask('deploy', ['cssmin', 'concat', 'uglify']); }; Gruntfile.js: Lets run it! $ grunt deploy Install plugin: $ npm install grunt-contrib-concat --save
What about SASS? Updated project structure: $ tree . .
├── public │ └── index.html ├── src │ ├── Gruntfile.js │ ├── js │ │ ├── jquery.js │ │ ├── app.js │ │ └── plugins.js │ ├── package.json │ └── sass │ ├── _plugins.scss │ └── app.scss └── static ├── css │ └── app.min.css └── js ├── app.all.js └── app.min.js #notification { width: 100%; font-size: 18px; text-align: center; padding: 15px 0; &.success { background: #1abc9c; } &.error { background: #e74c3c; } } _plugins.scss body { padding: 0; margin: 0; } @import "plugins"; app.scss
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { dist:
{ options: { outputStyle: 'compressed' }, files: { '../static/css/app.min.css': 'sass/app.scss' } } }, concat: { ... }, uglify: { ... } }); grunt.loadNpmTasks('grunt-sass'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.registerTask('default', ['sass', 'concat']); grunt.registerTask('deploy', ['sass', 'concat', 'uglify']); }; Gruntfile.js: Install plugin: $ npm install grunt-sass --save
Watching files
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), ... watch: {
sass: { files: ['sass/**/*.scss'], tasks: ['sass'] }, concat: { files: ['js/**/*.js'], tasks: ['concat'] }, uglify: { files: ['../static/js/app.all.js'], tasks: ['uglify'] } } }); ... grunt.loadNpmTasks("grunt-contrib-watch"); ... }; Gruntfile.js: Install plugin: $ npm install grunt-contrib-watch --save Watch changes: $ grunt watch
<!doctype html> <html> <head> <title>My Awesome WebApp</title> <link href="/static/css/app.min.css" type="text/css"
rel="stylesheet"/> </head> <body> ... <script src="/static/js/app.min.js" type="text/javascript"></script> </body> </html> index.html
None
None
body { padding: 0; margin: 0; } #left, #right {
width: 290px; height: 315px; float: left; margin-right: 10px; } #left { background: url('../images/left.jpg') no-repeat top left; } #right { background: url('../images/right.jpg') no-repeat top left; } @import "plugins"; app.scss
<!doctype html> <html> <head> <title>My Awesome WebApp</title> <link href="/static/css/app.min.css" type="text/css"
rel="stylesheet"/> </head> <body> ... <script src="/static/js/app.min.js" type="text/javascript"></script> </body> </html> index.html Number of requests: 5
module.exports = function(grunt) { grunt.initConfig({ pkg: grunt.file.readJSON('package.json'), sass: { ...
}, imageEmbed: { dist: { src: ['../static/css/app.min.css'], dest: '../static/css/app.min.css', options: {deleteAfterEncoding : false} } }, ... watch: { sass: { files: ['sass/**/*.scss'], tasks: ['sass', 'imageEmbed'] }, ... } }); grunt.loadNpmTasks("grunt-contrib-watch"); grunt.loadNpmTasks("grunt-image-embed"); grunt.registerTask('default', ['sass', 'imageEmbed', 'concat']); grunt.registerTask('deploy', ['sass', 'imageEmbed', 'concat', 'uglify']); }; Gruntfile.js: Install plugin: $ npm install grunt-image-embed --save
Number of requests: 3
OMG!
Thank you Marconi Moreto @marconimjr http://marconijr.com https://github.com/marconi