Brian P. Hogan
twitter: @bphogan
www.bphogan.com
grunt from the 

ground up
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
About me
• I build things	

• I write books	

• I teach people	

• I love...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Why are you here?
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
What is Grunt?
Grunt is a task runner written in JavaScript. It has advan...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
However, one of the worst ways to use Grunt is to just copy and paste peo...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Prerequisites
SO to do that let’s work with Grunt from the ground up. In ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Initial Setup
$	
  npm	
  install	
  grunt-­‐cli
$	
  cd	
  yourwebsite
$...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
The nom init command brings you through a wizard that asks a few question...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
package.json
{

"name": "awesomeco",

"version": "0.0.1",

"description":...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
So if we try to run the `grunt` command we get told that it can’t find “lo...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Installing Grunt to a
project
$	
  npm	
  install	
  grunt	
  -­‐-­‐save-...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
And so we install Grunt to our project and then when we try to run Grunt ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Gruntfile.js
'use strict'

module.exports = function(grunt){



};
The Gru...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
A task
'use strict';

module.exports = function(grunt){

grunt.registerTa...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
“Hello world”?
grunt.registerTask('hello', function(){

console.log("Hell...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Demo
Live demo
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Arguments




grunt.registerTask('greet', function(name){

grunt.log.writ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Errors?
grunt.registerTask('add', function(firstNumber, secondNumber){

f...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
External
'use strict';

module.exports = function(grunt){

grunt.register...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Loading External Tasks
grunt.loadTasks('tasks');

Code originally shown l...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Chaining
grunt.registerTask('default', ['praise', 'hello', 'greet:Brian']...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Simple tasks
• grunt.registerTask	

• arguments	

• external tasks (grunt...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Configuration
grunt.initConfig({

mainFile: 'index.html'

});
Grunt tasks ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
grunt.config.get
grunt.registerTask('printFile', function(){

var file = g...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Config Demo
grunt open:index.html
Chrome Firefox Safari
Let’s use configura...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Config
grunt.initConfig({

browsers: [

'open -a Firefox',

'open -a Safar...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
grunt.registerTask('open', function(file){

var browsers = grunt.config.g...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Multitasks
grunt build
basic version full version
Grunt’s multitasks let ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Our library
aquery
lib
a.js
b.js
vendor
jquery.js
So we’ll organize our c...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Config
grunt.config.init({

build: {

aquery: {

src: ['lib/a.js', 'lib/b....
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
The Task
grunt.registerMultiTask('build', 'Concatenate files.', function(...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Workflows with
plugins!
One of the things that makes Grunt so attractive i...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Our plan
sass sass/style.sass stylesheets/style.sass
cssmin stylesheets/s...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Using A Grunt Plugin
• $ npm install grunt-contrib-whatever	

• grunt.loa...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Plugin Config
grunt.initConfig({	
// other plugin configuration

concat: {...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
grunt.config()
grunt.config('concat', {

options: {

separator: ';',

},

...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Plugins we need
• grunt-contrib-sass	

• grunt-contrib-cssmin	

• grunt-c...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Demo!
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Sass
grunt.loadNpmTasks('grunt-contrib-sass');



grunt.config('sass', {
...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Watch for changes!
sass stylesheets/style.sass
Changes to
style.scss
We a...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Watch
grunt.loadNpmTasks('grunt-contrib-watch');

	
grunt.config('watch',...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
LiveReload
grunt.loadNpmTasks('grunt-contrib-watch');

grunt.config('watc...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Build
cssmin stylesheets/style.sass
build
sass
So then all we need to do ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Other Plugins?
• grunt-contrib-jshint	

• grunt-contrib-less	

• grunt-co...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Grunt
• Simple tasks	

• Multitasks	

• Plugins
Grunt is the standard for...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Grunt is there for you, to be used to automate everything that you need. ...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
http://pragprog.com/book/bhgrunt/
More? Here’s a shameless plug. In a cou...
Brian P. Hogan
twitter: @bphogan
www.bphogan.com
Questions?
Twitter: @bphogan
Upcoming SlideShare
Loading in …5
×

Grunt From The Ground Up

2,443 views

Published on

Modern web development requires managing CSS, JavaScript, HTML, and other assets, and things can get out of hand quickly. Grunt has become the standard for managing all of the tasks related to modern development, from concatenating files to minifying files for production. Unfortunately, most documentation on the Web focuses on how to cut and paste configuration files together. That’s not very helpful.

In this talk you'll learn how to use Grunt for a variety of purposes as we explore how it all works. We’ll cover how to develop Grunt tasks, how to work with files, how Multitasks work, and how to use Grunt and its plugin system to manage the development of a single page app that uses CoffeeScript, Sass, and Angular. When we’re done you’ll know exactly how Grunt works so you can use it on your own projects right away.

Published in: Software
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,443
On SlideShare
0
From Embeds
0
Number of Embeds
10
Actions
Shares
0
Downloads
11
Comments
0
Likes
1
Embeds 0
No embeds

No notes for slide

Grunt From The Ground Up

  1. 1. Brian P. Hogan twitter: @bphogan www.bphogan.com grunt from the 
 ground up
  2. 2. Brian P. Hogan twitter: @bphogan www.bphogan.com About me • I build things • I write books • I teach people • I love code!
  3. 3. Brian P. Hogan twitter: @bphogan www.bphogan.com Why are you here?
  4. 4. Brian P. Hogan twitter: @bphogan www.bphogan.com What is Grunt? Grunt is a task runner written in JavaScript. It has advantages and disadvantages to other build tools.
  5. 5. Brian P. Hogan twitter: @bphogan www.bphogan.com However, one of the worst ways to use Grunt is to just copy and paste people’s examples that you find online. There are lots of tutorials out there to follow, but before you start copying configurations around, you should learn how Grunt handles things under the hood.
  6. 6. Brian P. Hogan twitter: @bphogan www.bphogan.com Prerequisites SO to do that let’s work with Grunt from the ground up. In order to do this you’ll need two things: You’ll need NodeJS installed and you’ll need to be comfortable with the shell. The stuff we’ll do here today is code that works on my Mac. But it’ll work everywhere. !
  7. 7. Brian P. Hogan twitter: @bphogan www.bphogan.com Initial Setup $  npm  install  grunt-­‐cli $  cd  yourwebsite $  npm  init
  8. 8. Brian P. Hogan twitter: @bphogan www.bphogan.com The nom init command brings you through a wizard that asks a few questions about your project. The answers to these questions can be used by Grunt or other apps later. For example, Grunt can make your application name available as a variable when it writes files. You could also use this file as the source of your app’s version number.
  9. 9. Brian P. Hogan twitter: @bphogan www.bphogan.com package.json {
 "name": "awesomeco",
 "version": "0.0.1",
 "description": "This is my basic site",
 "main": "index.html",
 "scripts": {
 "test": "echo "Error: no test specified" && exit 1"
 },
 "author": "Brian Hogan",
 "license": "MIT"
 }
 Here’s how it works. That command creates the file package.json which contains all the things we specified. And what’s really important about this is that this file can also list the dependencies of our app.
  10. 10. Brian P. Hogan twitter: @bphogan www.bphogan.com So if we try to run the `grunt` command we get told that it can’t find “local grunt.”
  11. 11. Brian P. Hogan twitter: @bphogan www.bphogan.com Installing Grunt to a project $  npm  install  grunt  -­‐-­‐save-­‐dev The grunt-cli command we installed earlier lets us use the grunt command. But that doesn’t actually install Grunt. It just installs a command line tool that is designed to talk to the version of Grunt that is installed as an app dependency.
  12. 12. Brian P. Hogan twitter: @bphogan www.bphogan.com And so we install Grunt to our project and then when we try to run Grunt again it says we need a Gruntfile.
  13. 13. Brian P. Hogan twitter: @bphogan www.bphogan.com Gruntfile.js 'use strict'
 module.exports = function(grunt){
 
 }; The Gruntfile is how we configure our tasks. Our Gruntfile looks like this. ! The expression ‘use strict’ tells the JavaScript interpreter to be more strict on how it processes rules, raises errors, etc.
  14. 14. Brian P. Hogan twitter: @bphogan www.bphogan.com A task 'use strict';
 module.exports = function(grunt){
 grunt.registerTask("hello", function(){
 // your code here
 
 });
 };
 This is a task declaration. We “register the task” by giving it a name and a callback function that gets run. It’s like an event listener.
  15. 15. Brian P. Hogan twitter: @bphogan www.bphogan.com “Hello world”? grunt.registerTask('hello', function(){
 console.log("Hello World");
 }); There’s a simple task. Works great!!
  16. 16. Brian P. Hogan twitter: @bphogan www.bphogan.com
  17. 17. Brian P. Hogan twitter: @bphogan www.bphogan.com Demo Live demo
  18. 18. Brian P. Hogan twitter: @bphogan www.bphogan.com Arguments 
 
 grunt.registerTask('greet', function(name){
 grunt.log.writeln("Hello " + name);
 }); Code originally shown live during talk.
  19. 19. Brian P. Hogan twitter: @bphogan www.bphogan.com Errors? grunt.registerTask('add', function(firstNumber, secondNumber){
 firstNumber = Number(firstNumber);
 secondNumber = Number(secondNumber);
 
 if(isNaN(firstNumber)) grunt.warn("Nope! Why do you fail?????");
 if(isNaN(secondNumber)) grunt.warn("Nope! Why do you fail?????");
 
 var answer = firstNumber + secondNumber;
 grunt.log.writeln(answer);
 
 });
 Code originally shown live during talk.
  20. 20. Brian P. Hogan twitter: @bphogan www.bphogan.com External 'use strict';
 module.exports = function(grunt){
 grunt.registerTask('praise', function(){
 var praise = [
 "You're awesome!",
 "You are the best developer ever!",
 "You deserve a raise!",
 "You are good looking!",
 "Everyone likes you!"
 ];
 
 grunt.log.writeln(praise[Math.floor(Math.random() * praise.length)]);
 
 });
 };
 
 Code originally shown live during talk.
  21. 21. Brian P. Hogan twitter: @bphogan www.bphogan.com Loading External Tasks grunt.loadTasks('tasks');
 Code originally shown live during talk.
  22. 22. Brian P. Hogan twitter: @bphogan www.bphogan.com Chaining grunt.registerTask('default', ['praise', 'hello', 'greet:Brian']);
 grunt.registerTask('build', ['praise', 'hello']);
 
 Code originally shown live during talk.
  23. 23. Brian P. Hogan twitter: @bphogan www.bphogan.com Simple tasks • grunt.registerTask • arguments • external tasks (grunt.loadTasks) • Task chaining • default tasks So, we have the grunt.registerTask command to define a tasks. We can also define tasks that take arguments. We can have tasks defined outside of the Gruntfile and load those in, and we can define a task that calls other tasks. We can even have a default task that gets called when we type `grunt`.
  24. 24. Brian P. Hogan twitter: @bphogan www.bphogan.com Configuration grunt.initConfig({
 mainFile: 'index.html'
 }); Grunt tasks are better when they’re configured. We can set up a configuration object and add some stuff to it. !
  25. 25. Brian P. Hogan twitter: @bphogan www.bphogan.com grunt.config.get grunt.registerTask('printFile', function(){
 var file = grunt.config.get('mainFile');
 console.log(file); 
 }); Then we use grunt.config.get to grab the value out!
  26. 26. Brian P. Hogan twitter: @bphogan www.bphogan.com
  27. 27. Brian P. Hogan twitter: @bphogan www.bphogan.com Config Demo grunt open:index.html Chrome Firefox Safari Let’s use configuration to create a task that opens a page in all the browsers We’ll create a configuration for this and then write a task that launches the browsers that we configure.
  28. 28. Brian P. Hogan twitter: @bphogan www.bphogan.com Config grunt.initConfig({
 browsers: [
 'open -a Firefox',
 'open -a Safari',
 'open -a "Google Chrome"'
 ]
 }); Code originally shown live during talk.
  29. 29. Brian P. Hogan twitter: @bphogan www.bphogan.com grunt.registerTask('open', function(file){
 var browsers = grunt.config.get('browsers');
 
 var exec = require('child_process').exec;
 
 for (var index = 0; index < browsers.length; index++) {
 
 // tell Grunt to wait 
 var done = this.async();
 
 var command = browsers[index] + ' ' + file;
 grunt.log.writeln("Running " + command);
 var process = exec(command, function (error, stdout, stderr) {
 if (error) {
 if(error.code !== 0){
 grunt.warn(stderr);
 grunt.log.writeln(error.stack);
 
 }
 }
 // tell Grunt to get going again.
 done();
 });
 
 }
 }); Code originally shown live during talk.
  30. 30. Brian P. Hogan twitter: @bphogan www.bphogan.com Multitasks grunt build basic version full version Grunt’s multitasks let us build a single task that has many targets. Let’s say we’re doing our own JS framework. We want to build a basic version and a version that includes jQuery since our library depends on that. We’ll create two versions with one task.
  31. 31. Brian P. Hogan twitter: @bphogan www.bphogan.com Our library aquery lib a.js b.js vendor jquery.js So we’ll organize our code like this: our javascript files get split up into their own little files. We’ll put them in the lib/ folder. Then we’ll put jQuery in the vendor folder.
  32. 32. Brian P. Hogan twitter: @bphogan www.bphogan.com Config grunt.config.init({
 build: {
 aquery: {
 src: ['lib/a.js', 'lib/b.js'],
 dest: 'dist/aquery.js'
 },
 aqueryWithJquery: {
 src: ['lib/a.js', 'lib/b.js', 'vendor/jquery.js'],
 dest: 'dist/.aqueryFull.js'
 }
 }
 }); Multitasks can look at a task’s configuration for source and destination files. Here we’re specifying both versions.
  33. 33. Brian P. Hogan twitter: @bphogan www.bphogan.com The Task grunt.registerMultiTask('build', 'Concatenate files.', function() {
 var output = '';
 
 this.files.forEach(function(filegroup) { 
 
 var sources = filegroup.src.map(function(file){
 return(grunt.file.read(file));
 });
 
 output = sources.join(';');
 grunt.file.write(filegroup.dest, output);
 }); 
 
 });
 Then we use grunt’s multitask declaration, give it the same name as the configuration. and then we can iterate over the files. Grunt has utilities we can use to open the files, read the contents, and write new files. It’s pretty cool!
  34. 34. Brian P. Hogan twitter: @bphogan www.bphogan.com
  35. 35. Brian P. Hogan twitter: @bphogan www.bphogan.com Workflows with plugins! One of the things that makes Grunt so attractive is its huge library of plugins.
  36. 36. Brian P. Hogan twitter: @bphogan www.bphogan.com Our plan sass sass/style.sass stylesheets/style.sass cssmin stylesheets/style.sass stylesheets/style.sass
  37. 37. Brian P. Hogan twitter: @bphogan www.bphogan.com Using A Grunt Plugin • $ npm install grunt-contrib-whatever • grunt.loadNpmTasks(‘whatever'); • Add configuration.
  38. 38. Brian P. Hogan twitter: @bphogan www.bphogan.com Plugin Config grunt.initConfig({ // other plugin configuration
 concat: {
 options: {
 separator: ';',
 },
 dist: {
 src: ['src/intro.js', 'src/project.js', 'src/outro.js'],
 dest: 'dist/built.js',
 },
 }, // other plugin configuration.
 }); Here’s an example of a plugin config. But see… the examples in all the docs just tell you to paste a bunch of config options right in the main configuration.
  39. 39. Brian P. Hogan twitter: @bphogan www.bphogan.com grunt.config() grunt.config('concat', {
 options: {
 separator: ';',
 },
 dist: {
 src: ['src/intro.js', 'src/project.js', 'src/outro.js'],
 dest: 'dist/built.js',
 },
 }); But instead we can use grunt.config to put the code for each plugin in its own configuration block. This makes things much easier to maintain.
  40. 40. Brian P. Hogan twitter: @bphogan www.bphogan.com Plugins we need • grunt-contrib-sass • grunt-contrib-cssmin • grunt-contrib-watch So here are the plugins we’ll configure.
  41. 41. Brian P. Hogan twitter: @bphogan www.bphogan.com Demo!
  42. 42. Brian P. Hogan twitter: @bphogan www.bphogan.com Sass grunt.loadNpmTasks('grunt-contrib-sass');
 
 grunt.config('sass', {
 app: {
 files: {
 'stylesheets/style.css' : ['sass/style.scss']
 }
 }
 }); Code originally shown live during talk.
  43. 43. Brian P. Hogan twitter: @bphogan www.bphogan.com Watch for changes! sass stylesheets/style.sass Changes to style.scss We also want to watch for changes.
  44. 44. Brian P. Hogan twitter: @bphogan www.bphogan.com Watch grunt.loadNpmTasks('grunt-contrib-watch');
 grunt.config('watch', {
 styles: {
 files: ['sass/**/*.scss'],
 tasks: ['sass']
 }
 });

  45. 45. Brian P. Hogan twitter: @bphogan www.bphogan.com LiveReload grunt.loadNpmTasks('grunt-contrib-watch');
 grunt.config('watch', {
 options: {
 livereload: true
 },
 styles: {
 files: ['sass/**/*.scss'],
 tasks: ['sass']
 }
 });

  46. 46. Brian P. Hogan twitter: @bphogan www.bphogan.com Build cssmin stylesheets/style.sass build sass So then all we need to do is make a task that calls these parts. And you can do that with a task chain.
  47. 47. Brian P. Hogan twitter: @bphogan www.bphogan.com Other Plugins? • grunt-contrib-jshint • grunt-contrib-less • grunt-contrib-concat • grunt-contrib-coffee • grunt-contrib-uglify There are tons of Grunt plugins out there for you to work with. The JSHint plugin will scan your code for syntax and formatting issues. The Less plugin will let you use Less, another CSS preprocesssor. Into CoffeeScript? use that! You can even make your JavaScript smaller using Uglify. Or you can write your own Grunt plugin.
  48. 48. Brian P. Hogan twitter: @bphogan www.bphogan.com Grunt • Simple tasks • Multitasks • Plugins Grunt is the standard for JavaScript projects right now. Simple tasks are easy to define. Multitasks make it very easy to build a single task that builds multiple outputs, and plugins make Grunt incredibly flexible.
  49. 49. Brian P. Hogan twitter: @bphogan www.bphogan.com Grunt is there for you, to be used to automate everything that you need. If you have to do some repetitive task, you owe it to yourself to automate everything.
  50. 50. Brian P. Hogan twitter: @bphogan www.bphogan.com http://pragprog.com/book/bhgrunt/ More? Here’s a shameless plug. In a couple of weeks, this book will be available for you to own. And the two best questions will get a free ebook copy when it’s released.
  51. 51. Brian P. Hogan twitter: @bphogan www.bphogan.com Questions? Twitter: @bphogan

×