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
Assets Build Automation
Search
Marconi Moreto
February 25, 2014
Programming
2
310
Assets Build Automation
Automated building of your webapp assets using Gruntjs.
Marconi Moreto
February 25, 2014
Tweet
Share
More Decks by Marconi Moreto
See All by Marconi Moreto
Development Mini Toolbox
marconi
1
170
Introduction to Docker
marconi
4
1.3k
SaltStack 101
marconi
10
1.1k
Concurrency with Gevent
marconi
3
410
Django Quickstart
marconi
1
130
Other Decks in Programming
See All in Programming
AIとペアプロして処理時間を97%削減した話 #pyconshizu
kashewnuts
1
210
Unity6.3 AudioUpdate
cova8bitdots
0
120
Docコメントで始める簡単ガードレール
keisukeikeda
1
110
今更考える「単一責任原則」 / Thinking about the Single Responsibility Principle
tooppoo
3
1.6k
CSC307 Lecture 12
javiergs
PRO
0
470
AI時代のソフトウェア開発でも「人が仕様を書く」から始めよう-医療IT現場での実践とこれから
koukimiura
0
140
Swift ConcurrencyでよりSwiftyに
yuukiw00w
0
250
CSC307 Lecture 13
javiergs
PRO
0
310
モジュラモノリスにおける境界をGoのinternalパッケージで守る
magavel
0
3.5k
Go1.26 go fixをプロダクトに適用して困ったこと
kurakura0916
0
340
New in Go 1.26 Implementing go fix in product development
sunecosuri
0
390
文字コードの話
qnighy
44
17k
Featured
See All Featured
End of SEO as We Know It (SMX Advanced Version)
ipullrank
3
4.1k
Leadership Guide Workshop - DevTernity 2021
reverentgeek
1
230
コードの90%をAIが書く世界で何が待っているのか / What awaits us in a world where 90% of the code is written by AI
rkaga
60
42k
Side Projects
sachag
455
43k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
150
StorybookのUI Testing Handbookを読んだ
zakiyama
31
6.6k
How STYLIGHT went responsive
nonsquared
100
6k
Dominate Local Search Results - an insider guide to GBP, reviews, and Local SEO
greggifford
PRO
0
96
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
62
51k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
140
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.1k
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