Repetitive Tasks Ain't Sh*t

Andy McFee / @andymcfee

Follow along at home: bit.ly/grunt-gvarb

Who Are You?

Andy McFee

Front-end Guy, UX Designer, American Guy

What Is Grunt?

Automated tasks written in javascript* for javascript everything

*but it's not really javascript. Don't be scared.

One Tool to Rule Them All

pug quota ✓

Before Grunt?

soon.

So many tasks, so many tools

  • Pre-Processor Processors:
    • CodeKit
    • Hammer for Mac
    • Prepos
    • LiveReload
  • Command-line compiling
  • LiveReload
  • JS linters and hinters
  • Image Optimization

What does Grunt do?

  • Compile anything/everything
  • Minify Code
  • Lint code
  • Watch for changes
  • Run tests
  • Live refresh
  • Build zip folders
  • Copy and move files
  • Deploy
  • And more. Lots, lots more.

Get On With It!

What This Talk Covers

  1. Grunt Requirements
  2. Clean
  3. Copy
  4. Compile
  5. Build
  6. Other Plugins
  7. Other Tools
  8. Boston Terriers

Grunt Requirements

Saddle up, par'ner

You will need NodeJS and NPM

Install Grunt-CLI Globally*

grunt-cli = Grunt Command-Line Interface


  npm install -g grunt-cli
  

*You only have to do this once.

Add 2 Files to your Project Root

Gruntfile.js - The Grunt config file


  module.exports = function(grunt) {
    // Do grunt-related things in here
  };
  

package.json - npm packages file


  {
    "name": "my-project-name",
    "version": "0.1.0",
    "devDependencies": {
      "grunt": "~0.4.1"
    }
  }
  

Install npm modules


  npm install
  

Run npm install in the same directory as your package.json file to install all your node modules locally.

.gitignore


  node_modules
  

Be sure you add node_modules to your .gitignore.

Copy

Copy files from one place to another

follow along at home: bostons/1/

Install to project


  npm install --save-dev grunt-contrib-copy
  

Couple of things:

  • --save-dev will add the plugin to the package.json file automagically
  • You still need to add it manually to Gruntfile.js
  • Any plugin with -contrib- in its name is an offical plugin maintained by the grunt core team.

package.json


  {
    "name": "boston1",
    "version": "0.1.0",
    "devDependencies": {
      "grunt": "~0.4.1",
      "grunt-contrib-copy": "~0.4.1",
    }
  }
  

Gruntfile.js


  module.exports = function(grunt) {
    grunt.initConfig({

      copy: {
        main: {
          expand: true,
          cwd: 'src/',
          src: '**',
          dest: 'dist/',
          filter: 'isFile',
        }
      }

    });
    grunt.loadNpmTasks('grunt-contrib-copy');
  };
  

Command


  grunt copy
  

Result


  $ grunt copy
  Running "copy:main" (copy) task
  Copied 3 files

  Done, without errors.
  

All of the contents of the src/ were copied to a new folder called dist/

Yay.

Clean

Delete files

follow along at home: bostons/2/

package.json


  {
    "name": "boston2",
    "version": "0.1.0",
    "devDependencies": {
      "grunt": "~0.4.1",
      "grunt-contrib-clean": "~0.5.0",
      "grunt-contrib-copy": "~0.4.1"
    }
  }
  

Gruntfile.js


  module.exports = function(grunt) {
    grunt.initConfig({

      clean: {
        dist: ["dist"]
      },

      copy: {
        main: {
          expand: true,
          cwd: 'src/',
          src: '**',
          dest: 'dist/',
          filter: 'isFile',
        }
      }

    });
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
  };
  

Command


  grunt copy
  grunt clean
  

Result


  $ grunt clean
  Running "clean:dist" (clean) task
  Cleaning dist...OK

  Done, without errors.
  

The dist/ directory is deleted.

Yay.

Compiling

Compile from one language to another

follow along at home: bostons/3/

package.json


  {
    "name": "boston3",
    "version": "0.1.0",
    "devDependencies": {
      "grunt": "~0.4.1",
      "grunt-contrib-less": "~0.8.2"
    }
  }
  

Gruntfile.js


  module.exports = function(grunt) {
    grunt.initConfig({

      less: {
        src: {
          files: {
            "src/styles/main.css": "src/styles/main.less"
          }
        }
      }

    });
    grunt.loadNpmTasks('grunt-contrib-less');
  };
  

Command


  grunt less
  

Result


  $ grunt less
  Running "less:src" (less) task
  File src/styles/main.css created.

  Done, without errors.
  

src/styles/main.less is compiled into src/styles/main.css

Yay.

Building with Tasks

Let's do some heavy lifting!

follow along at home: bostons/4/

(the 'copy' portion of) Gruntfile.js


  copy: {
    dist: {
      expand: true,
      cwd: 'src/',
      src: ['**', '!styles/**'],
      dest: 'dist/',
      filter: 'isFile',
    }
  },
  

We are copying everything in the src/ directory except for the styles/ directory.

(the 'less' portion of) Gruntfile.js


  less: {
    src: {
      files: {
        "src/styles/main.css": "src/styles/main.less"
      }
    },
    dist: {
      files: {
        "dist/styles/main.css": "src/styles/main.less"
      }
    }
  }
  

Ooo, two targets! This will allow us to run grunt less:src to compile in the src/ directory or run grunt less:dist to compile to the dist/ directory. This is important.

(the 'registerTask' portion of) Gruntfile.js


  grunt.registerTask('build', [
    'clean',
    'less:dist',
    'copy'
  ]);

  grunt.registerTask('default', ['build']);
  

Ah, there they are! We've done two things here:

  1. Created a custom build task which we can run with grunt build
  2. Made the deafult task of grunt just run the build task

Commands

All three do the same thing:


  grunt clean
  grunt less:dist
  grunt copy
  

OR


  grunt build
  

OR


  grunt
  

Result


  $ grunt
  Running "clean:dist" (clean) task
  Cleaning dist...OK

  Running "less:dist" (less) task
  File dist/styles/main.css created.

  Running "copy:dist" (copy) task
  Copied 3 files

  Done, without errors.
  

Our src/ code was compiled and copied to a clean dist/ directory ready to be deployed.

Starting to see how this may be useful???

HURRY UP

This is supposed to be a short talk

No more example bostons :(

Compile Sass to CSS using Compass


  compass: {                  // Task
    dist: {                   // Target
      options: {              // Target options
        sassDir: 'sass',
        cssDir: 'css',
        environment: 'production'
      }
    },
    dev: {                    // Another target
      options: {
        sassDir: 'sass',
        cssDir: 'css'
      }
    }
  }
  

grunt-contrib-compass

Requires Ruby obv

Minify image files


  imagemin: {                          // Task
    dist: {
      files: [{
        expand: true,                  // Enable dynamic expansion
        cwd: 'src/',                   // Src matches are relative to this path
        src: ['**/*.{png,jpg,gif}'],   // Actual patterns to match
        dest: 'dist/'                  // Destination path prefix
      }]
    }
  }
  

grunt-contrib-imagemin

Watch Files; Run Tasks


  watch: {                        // Task
    css: {
      files: '**/*.{sass,scss}',  // Watch all Sass files
      tasks: ['sass'],            // Run "grunt sass" task on save
      options: {
        livereload: true,         // Reload the browser when this happens
      },
    },
  }
  

grunt-contrib-watch

Fire up a local webserver


  connect: {
    server: {
      options: {
        port: 9001,
        base: 'www-root'
      }
    }
  }
  

grunt-contrib-connect

So many plugins

Party Time

Yeoman - Bower - Assemble

Yeoman

Scaffolding workflows in seconds.

(ok maybe minutes in some cases.)

Bower

Front-end Package Management

Assemble

Static site generator for all the cool kids.

Questions?

Still not convinced?

That's all.

Slides available at bit.ly/grunt-gvarb

andymcfee.com

@andymcfee

andymcfee on github