Tutorial

A Simple Guide to Getting Started With Grunt

Draft updated on Invalid Date
    Default avatar

    By Chris on Code

    A Simple Guide to Getting Started With Grunt

    This tutorial is out of date and no longer maintained.

    Introduction

    During our web development workflows, there are many tasks that we have to repeat. These are tasks things like minifying JavaScript and CSS files, unit testing, linting your files to check for errors, compiling CSS preprocessor files (LESS, SASS), and much more.

    Grunt is a task runner. This means that those repetitive tasks we deal with in our daily workflow get automated. This will be a simple look at how to get up and running with Grunt. We will look at doing the basic tasks:

    • Linting our JS files
    • Minifying JS files
    • Compiling LESS files
    • Minifying CSS files
    • Watching our files for changes and doing the above tasks

    There are many tutorials out there that talk about the great things you can do with Grunt. While great, sometimes they come with confusing and fully-fledged configurations that are hard to understand for someone just getting into Grunt. This will be a guide in the basics of using Grunt and creating an incredibly simple and easy setup to handle the tasks mentioned above. This setup will teach us the basics but will let us think about how we can expand Grunt for future more advanced uses.

    Prerequisites

    To use Grunt, we will need to have Node.js installed. Don’t worry, you can use Grunt in any application you want, whether it is a Node app, a PHP app, WordPress, or just a plain old HTML/CSS/JS site. Node and its package manager (npm) are used to pull in the packages we need. Each package will have a different function like minifying or linting.

    If you don’t already have Node installed on your computer, go ahead and grab it and we’ll start working with Grunt. To make sure that you have Node and npm installed, go into your command line and type node -v and npm -v. If you see version numbers, then you’re ready to go!

    Setting Up the Project

    We’ll keep our project files very simple. This will be the file structure for our samples. Go ahead and create the folders and files shown. We’ll leave our files blank and start adding to them later.

    - dist              // will hold all our of final files (minified files)
    ----- css
    ----- js
    - src               // will hold all of our original files
    ----- css
    ---------- style.css
    ---------- pretty.less
    ----- js
    ---------- magic.js
    Gruntfile.js        // our Grunt configuration
    package.json        // our npm pacakge configuration (how we pull in packages)
    

    Notice how we have a src folder and a dist folder. We will be doing our work inside the src folder and Grunt will minify those files and save them into the dist folders. The files in dist are the ones that we will use for our final site.

    Grunt Packages

    When using npm, we define the packages we need in a package.json file. Let’s go into that file and add the packages we need. We’ll explain what each package does also.

    package.json
    {
      "name": "grunt-getting-started",
      "version": "0.1.0",
      "devDependencies": {
        "grunt": "~0.4.4",
        "grunt-contrib-jshint": "latest",
        "jshint-stylish": "latest",
        "grunt-contrib-uglify": "latest",
        "grunt-contrib-less": "latest",
        "grunt-contrib-cssmin": "latest",
        "grunt-contrib-watch": "latest"
      }
    }
    

    Here we have defined the name of our project, the version, and the devDependencies. This may seem weird at first for someone that hasn’t used Node or npm before, but you’ll see how npm is a very cool package manager for our project very soon.

    You may be wondering what all of the grunt-contrib-**** packages do. Here’s a handy table of the popular packages.

    Plugin Description
    contrib-jshint Validate files using JSHint
    contrib-uglify Minify files using UglifyJS
    contrib-watch Run tasks whenever watched files are changed
    contrib-clean Clean up files and folders
    contrib-copy Copy files and folders
    contrib-concat Combine files into a single file
    contrib-cssmin Compress CSS files
    contrib-less Compile LESS files to CSS
    contrib-imagemin Minify PNG, JPG, and GIFs
    contrib-compass Compile SASS to CSS using Compass
    contrib-htmlmin Minify HTML files

    For the full list of packages, visit the Grunt plugin repository.

    Now that we have the packages we need defined, let’s install them.

    Installing The Packages

    With our package.json file ready to go, go into your command line and type:

    1. npm install

    You will see npm do its thing and pull those packages into a newly created node_modules folder. Now we have these packages and are ready to use them in our project.

    Now that our setup is all ready to go, let’s set up our tasks for Grunt to do!

    Grunt Setup and Configuration

    To define our configuration for Grunt, we will use our Gruntfile.js file. This is the default place where our settings will go.

    In our Gruntfile.js, let’s go ahead and add in the basic things we need for our project.

    Gruntfile.js
    // our wrapper function (required by grunt and its plugins)
    // all configuration goes inside this function
    module.exports = function(grunt) {
    
      // ===========================================================================
      // CONFIGURE GRUNT ===========================================================
      // ===========================================================================
      grunt.initConfig({
    
        // get the configuration info from package.json ----------------------------
        // this way we can use things like name and version (pkg.name)
        pkg: grunt.file.readJSON('package.json'),
    
        // all of our configuration will go here
    
      });
    
      // ===========================================================================
      // LOAD GRUNT PLUGINS ========================================================
      // ===========================================================================
      // we can only load these if they are in our package.json
      // make sure you have run npm install so our app can find these
      grunt.loadNpmTasks('grunt-contrib-jshint');
      grunt.loadNpmTasks('grunt-contrib-uglify');
      grunt.loadNpmTasks('grunt-contrib-less');
      grunt.loadNpmTasks('grunt-contrib-cssmin');
      grunt.loadNpmTasks('grunt-contrib-watch');
    
    };
    

    We will use the module.exports (wrapper) function. This is the Node way of exposing our configuration to the rest of our application. We don’t have to worry about this too much, but if you are interested, read this great article on the topic.

    Inside of our grunt.initConfig(), we have taken the information from our package.json and saved it to pkg. With this, we can use the attributes from our package.json file. We can call the name of our project using pkg.name and the version with pkg.version. We could also expand this and even use an author.

    Why do we need this? Good question. We’ll see the usage in a bit, but one of the cool things we can do is use these attributes to create comments at the top of our files with the project name, author, date built, and version! Pretty neat.

    We have also loaded our Grunt plugins using grunt.loadNpmTasks(). This is the way we can use the plugins that we brought in earlier using npm.

    Package Configuration

    With our basic Grunt configuration ready, let’s look at configuring one of our packages. Let’s start with the JSHint package to lint our JavaScript files and tell us if there are any errors. This is the way for Grunt to know which files we want it to lint, minify, or anything else we want to do.

    When we configure packages, it will go into our grunt.initConfig() section and it will follow a certain structure. Here is the basic structure of configuring a Grunt package:

    Gruntfile.js
    grunt.initConfig({
    
        // configure jshint to validate js files -----------------------------------
        jshint: {
          options: {
            reporter: require('jshint-stylish') // use jshint-stylish to make our errors look and read good
          },
    
          // when this task is run, lint the Gruntfile and all js files in src
          build: ['Gruntfile.js', 'src/**/*.js']
        }
    
    });
    

    This will be the basic format for how we configure our packages. We will:

    • Call the name of the package (jshint)
    • Set options if we have to. These are usually found on the docs for each specific package
    • Create a build attribute and pass in files, directories, or anything else we want.

    Naming Conventions

    When naming the tasks, we are going to name our main task build. You can name this task what you want and you could even create more than one task. When you run Grunt, all of the tasks will automatically be run.

    If you wanted to create tasks within the jshint configuration, you could name them dev and production. Then we can call the tasks later by using jshint:dev or jshint:production.

    Now that we have seen the basic setup for a Grunt package, let’s go ahead and start creating configurations for the tasks we want to do.

    Linting JavaScript Files

    Here is the configuration for linting JavaScript files. It is the same as the example above. We are also bringing in the jshint-stylish package to make our error output look good.

    Gruntfile.js
    grunt.initConfig({
    
        ...
    
        // configure jshint to validate js files -----------------------------------
        jshint: {
          options: {
            reporter: require('jshint-stylish') // use jshint-stylish to make our errors look and read good
          },
    
          // when this task is run, lint the Gruntfile and all js files in src
          build: ['Grunfile.js', 'src/**/*.js']
        }
    
    });
    

    Go ahead and add in some JS into src/js/magic.js:

    src/js/magic.js
    var hello = 'look im grunting!'
    
    var awesome = 'yes it is awesome!'
    

    Now if we run in our command line:

    1. grunt jshint

    We’ll see it lint the Gruntfile and all JS files inside the src folder.

    We can tell it to watch all JS files in our application, specific files, or all the files in a given folder using the double asterisks (**) for all folders and single asterisk (*) for all files. With linting out of the way, let’s look at minifying.

    Minifying JavaScript Files

    We’ll follow the same format. We will call the uglify package, configure it, and tell it what files to use and create.

    grunt.initConfig({
    
        // get the configuration info from package.json ----------------------------
        // this way we can use things like name and version (pkg.name)
        pkg: grunt.file.readJSON('package.json'),
    
        ...
    
        // configure uglify to minify js files -------------------------------------
        uglify: {
          options: {
            banner: '/*\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n*/\n'
          },
          build: {
            files: {
              'dist/js/magic.min.js': 'src/js/magic.js'
            }
          }
        }
    
    });
    

    Here we are configuring an option called banner. This will add a nice comment to the top of our minified file. Notice we are using the pkg.name from the package.json file. In our build, we are defining the file we want to create (dist/js/magic.min.js) from the src file (src/js/magic.js).

    We will want more code in our file than just those two lines we made so let’s go grab a giant file to minify. Let’s go get jQuery.

    http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.js
    

    Copy everything from the unminified jQuery file and paste it into our src/js/magic.js file.

    See how they have their cool comment at the top of the file? We can build one of those out using the banner option. With our file, let’s go ahead and minify it. Go into your console and type:

    1. grunt uglify

    Now we have taken our file from the original 360kb to a nice sized 97.1kb!

    Minifying Multiple Files into One

    We can also do much more than just minify a single file. We can take multiple files and minify them to one output file. This can speed up our sites since we are only serving one JS file to the users visiting our site. To configure multiple files is straightforward:

    Gruntfile.js
    grunt.initConfig({
    
        // get the configuration info from package.json ----------------------------
        // this way we can use things like name and version (pkg.name)
        pkg: grunt.file.readJSON('package.json'),
    
        ...
    
        // configure uglify to minify js files -------------------------------------
        uglify: {
          options: {
            banner: '/*\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n*/\n'
          },
          build: {
            files: {
              'dist/js/magic.min.js': ['src/js/magic.js', 'src/js/magic2.js']
            }
          }
        }
    
    });
    

    In this example, we are taking these two files and minifying them into magic.min.js. We can also use the shortcut we learned earlier and just say all js files in the src folder should be minified. You would use (src/**/*.js) for that.

    Compiling LESS to CSS

    While we will be using LESS for this example, you can also use the grunt-contrib-compass package to do the same for SASS. Here’s our configuration for compiling LESS files. Like our minifying JS example, we will use our config to define the source and output files.

    Gruntfile.js
    grunt.initConfig({
    
        ...
    
        // compile less stylesheets to css -----------------------------------------
        less: {
          build: {
            files: {
              'dist/css/pretty.css': 'src/css/pretty.less'
            }
          }
        }
    
    });
    

    For this example, we aren’t going to be setting any options. Just compile our src/css/pretty.less to a dist/css/pretty.css file. Let’s add some LESS into our source file.

    src/css/pretty.less
    @red        : #CC594A;
    @yellow     : #B8CC24;
    @blue       : #8BC5FF;
    @purple     : #6F3596;
    
    body        {
        background:@red;
        color:@yellow;
    }
    
    button      {
        background:@blue;
    }
    
    div         {
        background:@purple;
    }
    

    Now we have defined some LESS variables and applied them to our elements. Let’s go ahead and run our task!

    1. grunt less

    Now we have created the dist/css/pretty.css file all of our LESS compiled to CSS and that file now looks like a normal stylesheet.

    dist/css/pretty.css
    body {
      background: #cc594a;
      color: #b8cc24;
    }
    button {
      background: #8bc5ff;
    }
    div {
      background: #6f3596;
    }
    

    Let’s look at two more things we can do with Grunt.

    Minifying CSS Files

    Like minifying JS files, this configuration will be straightforward. We get the drill now so let’s go ahead and create this configuration.

    Gruntfile.js
    grunt.initConfig({
    
        ...
    
        // configure cssmin to minify css files ------------------------------------
        cssmin: {
          options: {
            banner: '/*\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n*/\n'
          },
          build: {
            files: {
              'dist/css/style.min.css': 'src/css/style.css'
            }
          }
        }
    
    });
    

    Now if you run:

    1. grunt cssmin

    We will have our newly minified dist/css/style.min.css file.

    Running Multiple Tasks at Once

    Now that we see how all of our tasks work, let’s make things more efficient and run everything with just one task. This is much better than running separate calls for grunt uglify, grunt jshint, and so on.

    Default Task

    With Grunt, you can create tasks that will run multiple tasks at the same time. For example, let’s say we wanted to do all of our tasks above by just calling grunt. When you run grunt from the command line, Grunt will look for a task called default. Let’s create that now so we can see what it looks like.

    Gruntfile.js
    grunt.initConfig({
    
      ...
    
      // ============= // CREATE TASKS ========== //
      grunt.registerTask('default', ['jshint', 'uglify', 'cssmin', 'less']);
    
    
    });
    

    Now just run:

    1. grunt

    And all of the tasks in our default task will run!

    Now let’s look at how we can register different tasks for different environments.

    Different Tasks for Different Environments

    Let’s say we want to have Grunt work for us in a development environment and then when we go to production, we want different tasks to be run. We could define multiple tasks inside of each configuration. For example:

    Gruntfile.js
    grunt.initConfig({
    
      // get the configuration info from package.json ----------------------------
      // this way we can use things like name and version (pkg.name)
      pkg: grunt.file.readJSON('package.json'),
    
    ...
    
    // configure uglify to minify js files -------------------------------------
      uglify: {
        options: {
          banner: '/\n <%= pkg.name %> <%= grunt.template.today("yyyy-mm-dd") %> \n/\n'
        },
        dev: {
          files: { 'dist/js/magic.min.js': ['src/js/magic.js', 'src/js/magic2.js'] }
        },
        production: {
          files: { 'dist/js/magic.min.js': 'src/**/*.js' }
        }
      }
    });
    

    Now we can call them differently using a colon. Let’s create a task for development and production.

    Gruntfile.js
    grunt.initConfig({
    
      // ========= // CREATE TASKS =========
    
      // this default task will go through all configuration (dev and production) in each task
      grunt.registerTask('default', ['jshint', 'uglify', 'cssmin', 'less']);
    
      // this task will only run the dev configuration
      grunt.registerTask('dev', ['jshint:dev', 'uglify:dev', 'cssmin:dev', 'less:dev']);
    
      // only run production configuration
      grunt.registerTask('production', ['jshint:production', 'uglify:production', 'cssmin:production', 'less:production']);
    
    });
    

    Now we can call development by running:

    1. grunt dev

    Or production by running:

    1. grunt production

    Now we’ve seen how we can create multiple configurations for our tasks and call them differently.

    Let’s look at the last thing we’ll be creating today. We’ll watch our files and have Grunt run every time a file changes!

    Watching For Changes and Running Tasks

    The watch task will run every time a file is changed and saved. All we have to do is configure it to watch certain files and tell it what to do when those files are changed.

    We’re going to break from the basic build configuration we’ve been using. Here we’ll separate it out into stylesheets and scripts. We do this because we want to use different tasks for each.

    Gruntfile.js
    grunt.initConfig({
    
    ...
    
    // configure watch to auto update ----------------
    watch: {
    
      // for stylesheets, watch css and less files
      // only run less and cssmin stylesheets: {
      files: ['src//*.css', 'src//*.less'],
      tasks: ['less', 'cssmin'] },
    
      // for scripts, run jshint and uglify
      scripts: {
        files: 'src/**/*.js', tasks: ['jshint', 'uglify']
      }
    }
    
    });
    

    Now we have configured watch to watch our stylesheets and scripts. In your console, run:

    1. grunt watch

    Now we can see that Grunt will watch for changes and run the tasks it needs to.

    We changed a JavaScript file and a CSS file. The respective tasks were run and we can go on developing!

    This is a very powerful tool since we can do things like linting our files every time we save, compiling LESS, and we can even minify images.

    Conclusion

    Hopefully, this simplified look at Grunt will begin to grow some ideas about how to use Grunt for your specific workflow. Getting up and running is as easy as installing a package, configuring the package, and typing grunt!

    Definitely look through the official docs and the plugins list to get more ideas on how to use Grunt.

    Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.

    Learn more about us


    About the authors
    Default avatar
    Chris on Code

    author

    Still looking for an answer?

    Ask a questionSearch for more help

    Was this helpful?
     
    Leave a comment
    

    This textbox defaults to using Markdown to format your answer.

    You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!

    Try DigitalOcean for free

    Click below to sign up and get $200 of credit to try our products over 60 days!

    Sign up

    Join the Tech Talk
    Success! Thank you! Please check your email for further details.

    Please complete your information!

    Get our biweekly newsletter

    Sign up for Infrastructure as a Newsletter.

    Hollie's Hub for Good

    Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.

    Become a contributor

    Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.

    Welcome to the developer cloud

    DigitalOcean makes it simple to launch in the cloud and scale up as you grow — whether you're running one virtual machine or ten thousand.

    Learn more
    DigitalOcean Cloud Control Panel