Setting up a Build Chain with Grunt

23 min read

In this article by Bass Jobsen, author of the book Sass and Compass Designer’s Cookbook you will learn the following topics:

  • Installing Grunt
  • Installing Grunt plugins
  • Utilizing the Gruntfile.js file
  • Adding a configuration definition for a plugin
  • Adding the Sass compiler task

(For more resources related to this topic, see here.)

This article introduces you to the Grunt Task Runner and the features it offers to make your development workflow a delight. Grunt is a JavaScript Task Runner that is installed and managed via npm, the Node.js package manager. You will learn how to take advantage of its plugins to set up your own flexible and productive workflow, which will enable you to compile your Sass code. Although there are many applications available for compiling Sass, Grunt is a more flexible, versatile, and cross-platform tool that will allow you to automate many development tasks, including Sass compilation. It can not only automate the Sass compilation tasks, but also wrap any other mundane jobs, such as linting and minifying and cleaning your code, into tasks and run them automatically for you. By the end of this article, you will be comfortable using Grunt and its plugins to establish a flexible workflow when working with Sass. Using Grunt in your workflow is vital. You will then be shown how to combine Grunt’s plugins to establish a workflow for compiling Sass in real time. Grunt becomes a tool to automate integration testing, deployments, builds, and development in which you can use.

Finally, by understanding the automation process, you will also learn how to use alternative tools, such as Gulp. Gulp is a JavaScript task runner for node.js and relatively new in comparison to Grunt, so Grunt has more plugins and a wider community support. Currently, the Gulp community is growing fast. The biggest difference between Grunt and Gulp is that Gulp does not save intermediary files, but pipes these files’ content in memory to the next stream. A stream enables you to pass some data through a function, which will modify the data and then pass the modified data to the next function. In many situations, Gulp requires less configuration settings, so some people find Gulp more intuitive and easier to learn. In this article, Grunt has been chosen to demonstrate how to run a task runner; this choice does not mean that you will have to prefer the usage of Grunt in your own project. Both the task runners can run all the tasks described in this article. Simply choose the task runner that suits you best. This recipe demonstrates shortly how to compile your Sass code with Gulp. In this article, you should enter your commands in the command prompt. Linux users should open a terminal, while Mac users should run Terminal.app and Window users should use the cmd command for command line usage.

Installing Grunt

Grunt is essentially a Node.js module; therefore, it requires Node.js to be installed. The goal of this recipe is to show you how to install Grunt on your system and set up your project.

Getting ready

Installing Grunt requires both Node.js and npm. Node.js is a platform built on Chrome’s JavaScript runtime for easily building fast, scalable network applications, and npm is a package manager for Node.js. You can download the Node.js source code or a prebuilt installer for your platform at https://nodejs.org/en/download/. Notice that npm is bundled with node. Also, read the instructions at https://github.com/npm/npm#super-easy-install.

How to do it…

After installing Node.js and npm, installing Grunt is as simple as running a single command, regardless of the operating system that you are using. Just open the command line or the Terminal and execute the following command:

npm install -g grunt-cli

That’s it! This command will install Grunt globally and make it accessible anywhere on your system. Run the grunt –version command in the command prompt in order to confirm that Grunt has been successfully installed. If the installation is successful, you should see the version of Grunt in the Terminal’s output:

grunt --version

grunt-cli v0.1.11

After installing Grunt, the next step is to set it up for your project:

  1. Make a folder on your desktop and call it workflow. Then, navigate to it and run the npm init command to initialize the setup process:
  2. mkdir workflow && cd $_ && npm init
    Press Enter for all the questions and accept the defaults. You can change these settings later. This should create a file called package.json that will contain some information about the project and the project’s dependencies. In order to add Grunt as a dependency, install the Grunt package as follows:
  3. npm install grunt –save-dev
    Now, if you look at the package.json file, you should see that Grunt is added to the list of dependencies:
    ..."devDependencies": {"grunt": "~0.4.5"
    
    }

In addition, you should see an extra folder created. Called node_modules, it will contain Grunt and other modules that you will install later in this article.

How it works…

In the preceding section, you installed Grunt (grunt-cli) with the -g option. The -g option installs Grunt globally on your system. Global installation requires superuser or administrator rights on most systems. You need to run only the globally installed packages from the command line. Everything that you will use with the require() function in your programs should be installed locally in the root of your project. Local installation makes it possible to solve your project’s specific dependencies. More information about global versus local installation of npm modules can be found at https://www.npmjs.org/doc/faq.html.

There’s more…

Node package managers are available for a wide range of operation systems, including Windows, OSX, Linux, SunOS, and FreeBSD. A complete list of package managers can be found at https://github.com/joyent/node/wiki/Installing-Node.js-via-package-manager. Notice that these package managers are not maintained by the Node.js core team. Instead, each package manager has its own maintainer.

See also

  • The npm Registry is a public collection of packages of open source code for Node.js, frontend web apps, mobile apps, robots, routers, and countless other needs of the JavaScript community. You can find the npm Registry at https://www.npmjs.org/.
  • Also, notice that you do not have to use Task Runners to create build chains. Keith Cirkel wrote about how to use npm as a build tool at http://blog.keithcirkel.co.uk/how-to-use-npm-as-a-build-tool/.

Installing Grunt plugins

Grunt plugins are the heart of Grunt. Every plugin serves a specific purpose and can also work together with other plugins. In order to use Grunt to set up your Sass workflow, you need to install several plugins. You can find more information about these plugins in this recipe’s How it works… section.

Getting ready

Before you install the plugins, you should first create some basic files and folders for the project. You should install Grunt and create a package.json file for your project. Also, create an index.html file to inspect the results in your browser. Two empty folders should be created too. The scss folder contains your Sass code and the css folder contains the compiled CSS code.

Navigate to the root of the project, repeat the steps from the Installing Grunt recipe of this article, and create some additional files and directories that you are going to work with throughout the article. In the end, you should end up with the following folder and file structure:

How to do it…

Grunt plugins are essentially Node.js modules that can be installed and added to the package.json file in the list of dependencies using npm. To do this, follow the ensuing steps:

  1. Navigate to the root of the project and run the following command, as described in the Installing Grunt recipe of this article:
    npm init
  2. Install the modules using npm, as follows:
    npm install 
    
    grunt-contrib-sass 
    
    load-grunt-tasks 
    
    grunt-postcss 
    
    --save-dev

Notice the single space before the backslash in each line. For example, on the second line, grunt-contrib-sass , there is a space before the backslash at the end of the line. The space characters are necessary because they act as separators. The backslash at the end is used to continue the commands on the next line.

The npm install command will download all the plugins and place them in the node_modules folder in addition to including them in the package.json file. The next step is to include these plugins in the Gruntfile.js file.

How it works…

Grunt plugins can be installed and added to the package.json file using the npm install command followed by the name of the plugins separated by a space, and the –save-dev flag:

npm install nameOfPlugin1 nameOfPlugin2 --save-dev

The –save-dev flag adds the plugin names and a tilde version range to the list of dependencies in the package.json file so that the next time you need to install the plugins, all you need to do is run the npm install command. This command looks for the package.json file in the directory from which it was called, and will automatically download all the specified plugins. This makes porting workflows very easy; all it takes is copying the package.json file and running the npm install command. Finally, the package.json file contains a JSON object with metadata. It is also worth explaining the long command that you have used to install the plugins in this recipe. This command installs the plugins that are continued on to the next line by the backslash. It is essentially equivalent to the following:

npm install grunt-contrib-sass –-save-dev

npm install load-grunt-tasks –-save-dev

npm install grunt-postcss –-save-dev

As you can see, it is very repetitive. However, both yield the same results; it is up to you to choose the one that you feel more comfortable with. The node_modules folder contains all the plugins that you install with npm. Every time you run npm install name-of-plugin, the plugin is downloaded and placed in the folder.

If you need to port your workflow, you do not need to copy all the contents of the folder. In addition, if you are using a version control system, such as Git, you should add the node_modules folder to the .gitignore file so that the folder and its subdirectories are ignored.

There’s more…

Each Grunt plugin also has its own metadata set in a package.json file, so plugins can have different dependencies. For instance, the grunt-contrib-sass plugin, as described in the Adding the Sass compiler task recipe, has set its dependencies as follows:

"dependencies": {

    "async": "^0.9.0",

    "chalk": "^0.5.1",

    "cross-spawn": "^0.2.3",

    "dargs": "^4.0.0",

    "which": "^1.0.5"

  }

Besides the dependencies described previously, this task also requires you to have Ruby and Sass installed.

In the following list, you will find the plugins used in this article, followed by a brief description:

  • load-grunt-tasks: This loads all the plugins listed in the package.json file
  • grunt-contrib-sass: This compiles Sass files into CSS code
  • grunt-postcss: This enables you to apply one or more postprocessors to your compiled CSS code

CSS postprocessors enable you to change your CSS code after compilation.

In addition to installing plugins, you can remove them as well. You can remove a plugin using the npm uninstall name-of-plugin command, where name-of-plugin is the name of the plugin that you wish to remove. For example, if a line in the list of dependencies of your package.json file contains grunt-concurrent”: “~0.4.2”,, then you can remove it using the following command:

npm uninstall grunt-concurrent

Then, you just need to make sure to remove the name of the plugin from your package.json file so that it is not loaded by the load-grunt-tasks plugin the next time you run a Grunt task. Running the npm prune command after removing the items from the package.json file will also remove the plugins. The prune command removes extraneous packages that are not listed in the parent package’s dependencies list.

See also

  • More information on the npm version’s syntax can be found at https://www. npmjs.org/doc/misc/semver.html
  • Also, see http://caniuse.com/ for more information on the Can I Use database

Utilizing the Gruntfile.js file

The Gruntfile.js file is the main configuration file for Grunt that handles all the tasks and task configurations. All the tasks and plugins are loaded using this file. In this recipe, you will create this file and will learn how to load Grunt plugins using it.

Getting ready

First, you need to install Node and Grunt, as described in the Installing Grunt recipe of this article. You will also have to install some Grunt plugins, as described in the Installing Grunt plugins recipe of this article.

How to do it…

Once you have installed Node and Grunt, follow these steps:

  1. In your Grunt project directory (the folder that contains the package.json file), create a new file, save it as Gruntfile.js, and add the following lines to it:
    module.exports = function(grunt) {
    
      grunt.initConfig({
    
        pkg: grunt.file.readJSON('package.json'),
    
     
    
        //Add the Tasks configurations here.
    
      });
    
    // Define Tasks here
    
    };
  2. This is the simplest form of the Gruntfile.js file that only contains two information variables.
  3. The next step is to load the plugins that you installed in the Installing Grunt plugins recipe. Add the following lines at the end of your Gruntfile.js file:
    grunt.loadNpmTasks('grunt-sass');
  4. In the preceding line of code, grunt-sass is the name of the plugin you want to load.

That is all it takes to load all the necessary plugins. The next step is to add the configurations for each task to the Gruntfile.js file.

How it works…

Any Grunt plugin can be loaded by adding a line of JavaScript to the Gruntfile.js file, as follows:

grunt.loadNpmTasks('name-of-module');

This line should be added every time a new plugin is installed so that Grunt can access the plugin’s functions. However, it is tedious to load every single plugin that you install. In addition, you will soon notice that, as your project grows, the number of configuration lines will increase as well.

The Gruntfile.js file should be written in JavaScript or CoffeeScript. Grunt tasks rely on configuration data defined in a JSON object passed to the grunt.initConfig method. JavaScript Object Notation (JSON) is an alternative for XML and used for data exchange. JSON describes name-value pairs written as “name”: “value”. All the JSON data is separated by commas with JSON objects written inside curly brackets and JSON arrays inside square brackets. Each object can hold more than one name/value pair with each array holding one or more objects.

You can also group tasks into one task. Your alias groups of tasks using the following line of code: grunt.registerTask(‘alias’,[‘task1’, ‘task2’]);

There’s more…

Instead of loading all the required Grunt plugins one by one, you can load them automatically with the load-grunt-tasks plugin. You can install this by using the following command in the root of your project:

npm install load-grunt-tasks --save-dev

Then, add the following line at the very beginning of your Gruntfile.js file after module.exports:

require('load-grunt-tasks')(grunt);

Now, your Gruntfile.js file should look like this:

module.exports = function(grunt) {

  require('load-grunt-tasks')(grunt);

  grunt.initConfig({

    pkg: grunt.file.readJSON('package.json'),

 

    //Add the Tasks configurations here.

  });

// Define Tasks here

};

The load-grunt-tasks plugin loads all the plugins specified in the package.json file. It simply loads the plugins that begin with the grunt- prefix or any pattern that you specify. This plugin will also read dependencies, devDependencies, and peerDependencies in your package.json file and load the Grunt tasks that match the provided patterns.

A pattern to load specifically chosen plugins can be added as a second parameter. You can load, for instance, all the grunt-contrib tasks with the following code in your Gruntfile.js file:

require('load-grunt-tasks')(grunt, {pattern: 'grunt-contrib-*'});

See also

Read more about the load-grunt-tasks module at https://github.com/sindresorhus/load-grunt-task

Adding a configuration definition for a plugin

Any Grunt task needs a configuration definition. The configuration definitions are usually added to the Gruntfile.js file itself and are very easy to set up. In addition, it is very convenient to define and work with them because they are all written in the JSON format. This makes it very easy to spot the configurations in the plugin’s documentation examples and add them to your Gruntfile.js file.

In this recipe, you will learn how to add the configuration for a Grunt task.

Getting ready

For this recipe, you will first need to create a basic Gruntfile.js file and install the plugin you want to configure. If you want to install the grunt-example plugin, you can install it using the following command in the root of your project:

npm install grunt-example –save-dev

How to do it…

Once you have created the basic Gruntfile.js file (also refer to the Utilizing the Gruntfile.js file recipe of this article), follow this step:

  1. A simple form of the task configuration is shown in the following code. Start by adding it to your Gruntfile.js file wrapped inside grunt.initConfig{}:
    example: {
    
      subtask: {
    
       files: {
    
         "stylesheets/main.css":
    
         "sass/main.scss"
    
        }
    
      }
    
    }

How it works…

If you look closely at the task configuration, you will notice the files field that specifies what files are going to be operated on. The files field is a very standard field that appears in almost all the Grunt plugins simply due to the fact that many tasks require some or many file manipulations.

There’s more…

The Don’t Repeat Yourself (DRY) principle can be applied to your Grunt configuration too.

First, define the name and the path added to the beginning of the Gruntfile.js file as follows:

app {

 dev : "app/dev"

}

Using the templates is a key in order to avoid hard coded values and inflexible configurations. In addition, you should have noticed that the template has been used using the <%= %> delimiter to expand the value of the development directory:


"<%= app.dev %>/css/main.css": "<%= app.dev %>/scss/main.scss"

 

The <%= %> delimiter essentially executes inline JavaScript and replaces values, as you can see in the following code:

 

"app/dev/css/main.css": "app/dev/scss/main.scss"

So, put simply, the value defined in the app object at the top of the Gruntfile.js file is evaluated and replaced.

If you decide to change the name of your development directory, for example, all you need to do is change the app’s variable that is defined at the top of your Gruntfile.js file.

Finally, it is also worth mentioning that the value for the template does not necessarily have to be a string and can be a JavaScript literal.

See also

You can read more about templates in the Templates section of Grunt’s documentation at http://gruntjs.com/configuring- tasks#templates

Adding the Sass compiler task

The Sass tasks are the core task that you will need for your Sass development. It has several features and options, but at the heart of it is the Sass compiler that can compile your Sass files into CSS. By the end of this recipe, you will have a good understanding of this plugin, how to add it to your Gruntfile.js file, and how to take advantage of it.

In this recipe, the grunt-contrib-sass plugin will be used. This plugin compiles your Sass code by using Ruby Sass. You should use the grunt-sass plugin to compile Sass into CSS with node-sass (LibSass).

Getting ready

The only requirement for this recipe is to have the grunt-contrib-sass plugin installed and loaded in your Gruntfile.js file. If you have not installed this plugin in the Installing Grunt Plugins recipe of this article, you can do this using the following command in the root of your project:

npm install grunt-contrib-sass --save-dev

You should also install grunt local by running the following command:

npm install grunt --save-dev

Finally, your project should have the file and directory, as describe in the Installing Grunt plugins recipe of this article.

How to do it…

  1. An example of the Sass task configuration is shown in the following code. Start by adding it to your Gruntfile.js file wrapped inside the grunt.initConfig({}) code.
  2. Now, your Gruntfile.js file should look as follows:
    module.exports = function(grunt) {
    
      grunt.initConfig({
    
        //Add the Tasks configurations here.
    
        sass: {                                     
    
          dist: {                                   
    
            options: {                            
    
              style: 'expanded'
    
            },
    
            files: {                                
    
            'stylesheets/main.css': 'sass/main.scss'  'source'
    
            }
    
          }
    
        }
    
      });
    
     
    
      grunt.loadNpmTasks('grunt-contrib-sass');
    
     
    
      // Define Tasks here 
    
      grunt.registerTask('default', ['sass']); 
    
    }
  1. Then, run the following command in your console:
  2. grunt sass
    The preceding command will create a new stylesheets/main.css file. Also, notice that the stylesheets/main.css.map file has also been automatically created. The Sass compiler task creates CSS sourcemaps to debug your code by default.

How it works…

In addition to setting up the task configuration, you should run the Grunt command to test the Sass task. When you run the grunt sass command, Grunt will look for a configuration called Sass in the Gruntfile.js file. Once it finds it, it will run the task with some default options if they are not explicitly defined. Successful tasks will end with the following message:

Done, without errors.

There’s more…

There are several other options that you can include in the Sass task. An option can also be set at the global Sass task level, so the option will be applied in all the subtasks of Sass.

In addition to options, Grunt also provides targets for every task to allow you to set different configurations for the same task. In other words, if, for example, you need to have two different versions of the Sass task with different source and destination folders, you could easily use two different targets. Adding and executing targets are very easy. Adding more builds just follows the JSON notation, as shown here:

   sass: {                                      // Task

      dev: {                                    // Target

        options: {                               // Target options

          style: 'expanded'

        },

        files: {                                 // Dictionary of files

        'stylesheets/main.css': 'sass/main.scss' // 'destination': 'source'

        }

      },

      dist: {                      

        options: {             

          style: 'expanded',

          sourcemap: 'none'         

        },

        files: {                             

        'stylesheets/main.min.css': 'sass/main.scss'

        }

      }

    }

In the preceding example, two builds are defined. The first one is named dev and the second is called dist. Each of these targets belongs to the Sass task, but they use different options and different folders for the source and the compiled Sass code.

Moreover, you can run a particular target using grunt sass:nameOfTarget, where nameOfTarge is the name of the target that you are trying to use. So, for example, if you need to run the dist target, you will have to run the grunt sass:dist command in your console. However, if you need to run both the targets, you could simply run grunt sass and it would run both the targets sequentially.

As already mentioned, the grunt-contrib-sass plugin compiles your Sass code by using Ruby Sass, and you should use the grunt-sass plugin to compile Sass to CSS with node-sass (LibSass).

To switch to the grunt-sass plugin, you will have to install it locally first by running the following command in your console:

npm install grunt-sass

Then, replace grunt.loadNpmTasks(‘grunt-contrib-sass’); with grunt.loadNpmTasks(‘grunt-sass’); in the Gruntfile.js file; the basic options for grunt-contrib-sass and grunt-sass are very similar, so you have to change the options for the Sass task when switching to grunt-sass.

Finally, notice that grunt-contrib-sass also has an option to turn Compass on.

See also

  • Please refer to Grunt’s documentation for a full list of options, which is available at https://gruntjs/grunt-contrib-sass#options
  • Also, read Grunt’s documentation for more details about configuring your tasks and targets at http://gruntjs.com/configuring-tasks#task-configuration-and-targets github.com/

Summary

In this article you studied about installing Grunt, installing Grunt plugins, utilizing the Gruntfile.js file, adding a configuration definition for a plugin and adding the Sass compiler task.

Resources for Article:


Further resources on this subject:


Packt

Share
Published by
Packt

Recent Posts

Top life hacks for prepping for your IT certification exam

I remember deciding to pursue my first IT certification, the CompTIA A+. I had signed…

3 years ago

Learn Transformers for Natural Language Processing with Denis Rothman

Key takeaways The transformer architecture has proved to be revolutionary in outperforming the classical RNN…

3 years ago

Learning Essential Linux Commands for Navigating the Shell Effectively

Once we learn how to deploy an Ubuntu server, how to manage users, and how…

3 years ago

Clean Coding in Python with Mariano Anaya

Key-takeaways:   Clean code isn’t just a nice thing to have or a luxury in software projects; it's a necessity. If we…

3 years ago

Exploring Forms in Angular – types, benefits and differences   

While developing a web application, or setting dynamic pages and meta tags we need to deal with…

3 years ago

Gain Practical Expertise with the Latest Edition of Software Architecture with C# 9 and .NET 5

Software architecture is one of the most discussed topics in the software industry today, and…

3 years ago