Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases now! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Getting Started with Grunt: The JavaScript Task Runner
Getting Started with Grunt: The JavaScript Task Runner

Getting Started with Grunt: The JavaScript Task Runner: If you know JavaScript you ought to know Grunt – the Task Runner for managing sophisticated web applications. From a basic understanding to constructing your own advanced Grunt tasks, this tutorial has it all covered.

eBook
$15.99 $22.99
Paperback
$38.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Table of content icon View table of contents Preview book icon Preview Book

Getting Started with Grunt: The JavaScript Task Runner

Chapter 1. Introducing Grunt

In this chapter, we will first define Grunt and cover some of the reasons why we would want to use it. Then, instead of starting at the beginning, we'll temporarily jump ahead to review some real-world use cases. Each example will contain a brief summary, but it won't be covered in detail, as the purpose is to provide a glimpse of what is to come. These examples will also provide us with a general understanding of what to expect from Grunt and hopefully, with this sneak peak, an idea of how Grunt's power and simplicity could be applied to our own projects.

What is Grunt?


When Ben Alman released Grunt (http://gswg.io#grunt) in March 2012, he described it as a task-based command line build tool for JavaScript projects. Now, with the release of Grunt version 0.4.x, the project caption is The JavaScript Task Runner. Build tools or task runners are most commonly used for automating repetitive tasks, though we will see that the benefits of using Grunt far exceed simple automation.

The terms build tool and task runner essentially mean the same thing and throughout this book, I will always use build tool, though both can be used interchangeably. Build tools are programs with the sole purpose of executing code to convert some source code into a final product, whether it be a complete web application, a small JavaScript library or even a Node.js command-line tool. This build process can be composed of any number of steps, including: style and coding practice enforcement, compiling, file watching and automatic task execution, and unit testing and end-to-end testing, just to name a few.

Grunt has received huge success in the open-source community, especially with the rise of JavaScript following the world's increasing demand for web applications. At the time of writing this book (December 2013), Grunt is downloaded approximately 300,000 times per month (http://gswg.io#grunt-stats) and the open-source community has published approximately 1,400 Grunt plugins in npm (the Node.js package manager http://gswg.io#npm) and these numbers continue to rise.

Node.js (http://gswg.io#node) is a platform for writing JavaScript command-line tools, which run on all major operating systems. Grunt is one such command-line tool. Once installed, we can execute grunt on the command line. This tells Grunt to look for a Gruntfile.js file. This choice of name refers to the build tool Make, and its Makefile. This file is the entry point to our build, which can define tasks inline, load tasks from external files, load tasks from external modules, and configure these tasks and much more.

Let's briefly review a simple example of a Gruntfile.js file so we can get a glimpse of what is to come:

//Code example 01-minify
module.exports = function(grunt) {

  // Load the plugin that provides the "uglify" task.
  grunt.loadNpmTasks('grunt-contrib-uglify');

  // Project configuration.
  grunt.initConfig({
    uglify: {
      target1: {
        src: 'foo.js',
        dest: 'foo.min.js'
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['uglify']);
};

In this short example, we are using the uglify plugin to create a minified (or compressed) version of our main project file—foo.js in this case. First, we load the plugin with loadNpmTasks. Next, we'll configure it by passing a configuration object to initConfig. Finally, we'll define a default task, which in this example, is simply an alias to the uglify task.

Now, we can run the default task with grunt and we should see the following output:

$ grunt
Running "uglify:target1" (uglify) task
File "foo.min.js" created.
Done, without errors.

We've just created and successfully run our first Grunt build!

Why use Grunt?


In the past five years, due to the evolution of Web browsers, focus has shifted from Desktop applications to Web applications. More companies are realizing that the web is a perfect platform to create tools to save people time and money by providing quick and easy access to their service. Whether it is ordering pizza or Internet banking, web applications are fast becoming the platform of choice for the modern business. These modern companies know that, if they were to build an application for a specific platform, like the iOS or Windows operating systems, they would be inherently restricting their audience, as each operating system has its own percentage of the total user base. They've realized that in order to reach everyone, they need a ubiquitous platform that exists in all operating systems. This platform is the Web. So, if everyone with Internet access has a browser, then by targeting the browser as our platform, our potential user base becomes everyone on the Internet.

The Google product line is a prime example of a business successfully utilizing the browser platform. This product line includes: Google Search, YouTube, Gmail, Google Drive, Google Docs, Google Calendar, and Google Maps. However, providing a rich user experience comes with a cost. These applications are tremendously more complex than a traditional website made with jQuery animated menus.

Complex JavaScript Web Applications require considerable design and planning. It is quite common for the client-side (or browser) JavaScript code to be more complicated than the server-side code. With this in mind, we need to ensure our code base is manageable and maintainable. The key to code manageability and maintainability is to logically structure our project and to keep our code DRY. Structuring includes the file and directory structure as well as the code structure (that is HTML, CSS, and JavaScript structure). Maintaining a logical directory structure provides predefined locations for all types of files. This allows us to always know where to put our code, which is very important for rapid development. DRY stands for Don't Repeat Yourself (http://gswg.io#dry). Hence, to keep your code DRY is to write code where there is little or no repetition and we embrace the idea of a "single source of truth". Similarly, we want to avoid repetition surrounding our build process. As we'll see throughout this book, Grunt is a great tool for achieving these goals.

Benefits of Grunt


Many people are of the opinion that the benefit of using Grunt (or any build tool for that matter) is to possibly save time, and often this tradeoff—of learning time versus actual development time is deemed too risky, which then leads to the programmer staying safe with the manual method. This perception is misguided. The added efficiency is only one of benefits of using Grunt, the other main benefits include: build consistency, increased effectiveness, community utilization, and task flexibility.

Efficiency

Hypothetically, let's say it takes us 2 minutes per build and we need to build (and run the tests) numerous times every hour, resulting in approximately 50 builds per day. With this schedule, it costs us approximately 100 minutes per day in order to perform the monotonous task of manual running various sets of command-line tools in the right sequence. Now, if learning a new build tool like Grunt takes us 2-3 hours of research and 1-2 hours to implement the existing build process as a Grunt build, then this cost will be recovered in only a week of work. Considering that most programmers will be using their trade for years to come, the decision is simple—use a build tool as it is well worth the time investment.

With this in mind, we can see the time spent to learn a new tool like Grunt is negligible in comparison with the time saved across the entire span of all projects in which that tool is used.

Consistency

The human propensity for error is an unavoidable hurdle programmers face when carrying out a manual build process. This propensity is further increased if a given build process involves each command being manually typed out instead of saving them in some kind of script for easier execution. Even with an array of scripts, problems can still arise if someone forgets to execute one, or if the special script required for a special situation is forgotten.

Using Grunt provides us with the ability to implement our build logic inside the build process. Once the build has been set up and confirmed, this effectively removes the possibility for human error from the equation entirely. This ability also helps newcomers contribute to your projects by allowing them to quickly get started on the code base as opposed to getting bogged down trying to understand the build.

Also, as a result of the great effort behind the Node.js project, we can also run our encapsulated build process across all major operating systems. This allows developers from all walks of life to use and enhance a common build process.

Effectiveness

As well as saving time from doing less, we also save time by staying in the zone. For many programmers, it often takes us some time to gather momentum in order to bring our brains into gear. By automating the build process, we multi-task less, allowing us to keep our minds focused on the current task at hand.

Community

A common problem for many build tools is the lack of community support. Most build tool have plugins for many common build processes, but as soon as we want to perform a task that is too niche or too advanced, we are likely to be forced to restart from scratch.

At the time of writing, npm (the Node.js Package Manager) contained approximately 50,000 modules and, as mentioned above, approximately 1,900 of these are Grunt plugins. These plugins cover a wide array of build problems and are available now via the public npm repository, which provides a purposefully simple means to publish new modules to the repository. As a result of this simplicity, anyone may share their Grunt plugin with the rest of the world with a single npm publish command. This concept makes it easy for programmers of every skill level to share their work. Allowing everyone to build upon everyone else's work creates a synergistic community, where the more people contribute, the more valuable the community becomes, which in turn provides further incentive for people to contribute. So, by using Grunt, we tap into the power of the Node.js community. This fact alone should be enough to convince us to use Grunt.

GitHub (http://gswg.io#github) is another valuable community tool that greatly benefits Grunt. As of June 2013, JavaScript code makes up 21 percent of code on GitHub making it the most popular programming language on GitHub. However, this fact alone is not the only reason to host your project on GitHub. The Git (http://gswg.io#git) Distributed Version Control System (DVCS) provides the ability to branch and merge code, and the flexibility of both local and remote repositories. This makes it the superior choice for open-source collaboration, compared to other (non-distributed) VCS tools such as SVN or TFS.

With the combination of GitHub (being a great JavaScript open-source collaboration platform) and npm (being so widespread and simple to use) the Grunt team provides Grunt users with the perfect environment for an open-source community to thrive.

We'll cover more on npm in the Chapter 2, Setting Up Grunt and contributing to open-source projects in Chapter 5, Advanced Grunt.

Flexibility

Another common problem for many build tools is the level of prior knowledge required to write your own task. Often, they also require varying levels of setup before you can start actually writing code. A Grunt task is essentially just a JavaScript function, and that's it. Tasks can be defined with various levels of complexity to suit the needs of build process. However, remaining at the root of all tasks is the idea of one task being one function—for example, this Gruntfile.js defines a simple task called foo:

//Code example 02-simple-task
module.exports = function(grunt) {

  grunt.registerTask('foo', function() {
    grunt.log.writeln('foo is running...');
  });

};

Our new foo task is runnable with the command: grunt foo. When executed, we see:

$ grunt foo
Running "foo" task
foo is running...

We'll learn more about Grunt tasks in Chapter 3, Using Grunt.

The arguments for using various build tools generally stem from two conflicting sides: the simplicity of configuration or the power of scripting. With Grunt however, we get the best of both worlds. We are able to easily create arbitrary tasks as well as define verbose configuration. The following Gruntfile.js file demonstrates this:

//Code example 03-simple-config
module.exports = function(grunt) {

  grunt.initConfig({
    bar: {
      foo: 42
    }
  });

  grunt.registerTask('bar', function() {
    var bar = grunt.config.get('bar');
    var bazz = bar.foo + 7;
    grunt.log.writeln("Bazz is " + bazz);
  });
};

In this example, we are first initializing the configuration with an object. Then, we are registering a simple task, which uses this configuration. Note, instead of using grunt.initConfig(…) in the preceding code, we could also use grunt.config.set('bar', { foo: 42 }); to achieve the same result.

When we run this example with grunt bar, we should see:

$ grunt bar
Running "bar" task
Bazz is 49

This example demonstrates the creation of a simple task using minimal configuration. Imagine we have created a task which parses JavaScript source code into a tree of syntax nodes, traverses these nodes, performing arbitrary transforms on them (like shortening variable names) and writes them back out to a file, with the ultimate effect of compressing our source code. This is exactly what the UglifyJS library does, with many configuration options to customize its operation. We'll cover more on JavaScript Minification in the next section.

Real-world use cases


Hearing about the benefits of Grunt is all well and good, but what about actual use cases that the average web developer will face every day in the real world? In this section, we'll take an eagle-eye view of the most common use cases for Grunt.

These examples make use of configuration targets. Essentially, targets allow us to define multiple configurations for a task. We'll cover more on configuration targets in Chapter 2, Setting Up Grunt.

Static analysis or Linting

In programming, the term linting is the process of finding probable bugs and/or style errors. Linting is more popular in dynamically typed languages as type errors may only be resolved at runtime. Douglas Crockford popularized JavaScript linting in 2011 with the release of his popular tool, JSLint.

JSLint is a JavaScript library, so it can be run in Node.js or in a browser. JSLint is a set of predetermined rules that enforce correct JavaScript coding practices. Some of these rules may be optionally turned on and off, however, many cannot be changed. A complete list of JSLint rules can be found at http://gswg.io#jslint-options.

This leads us to JSHint. Due to Douglas Crockford's coding style being too strict for some, Anton Kovalyov has forked the JSLint project to create a similar, yet more lenient version, which he aptly named: JSHint.

I am a fan of Douglas Crockford and his book, JavaScript—The Good Parts (http://gswg.io#the-good-parts), but like Anton, I prefer a more merciful linter, so in this example below, we will use the Grunt plugin for JSHint: http://gswg.io#grunt-contrib-jshint.

//Code example 04-linting
//Gruntfile.js
module.exports = function(grunt) {

  // Load the plugin that provides the "jshint" task.
  grunt.loadNpmTasks('grunt-contrib-jshint');

  // Project configuration.
  grunt.initConfig({
    jshint: {
      options: {
        curly: true,
        eqeqeq: true
      },
      target1: ['Gruntfile.js', 'src/**/*.js']
    }
  });

  // Define the default task
  grunt.registerTask('default', ['jshint']);

};

//src/foo.js
if(7 == "7") alert(42); 

In the preceding code, we first load the jshint task. We then configure JSHint to run on the Gruntfile.js file itself, as well as all of the .js files in the src directory and its subdirectories (which is src/foo.js in this case). We also set two JSHint options: curly, which ensures that curly braces are always used in if, for, and while statements; and eqeqeq, which ensures that strict equality === is always used.

JSHint has retained most of the optional rules from JSLint and it has also added many more. These rules can be found at: http://gswg.io#jshint-options.

Finally, we can run the jshint task with grunt, and we should see the following:

$ grunt
Running "jshint:target1" (jshint) task
Linting src/foo.js...ERROR
[L1:C6] W116: Expected '===' and instead saw '=='.
if(7 == "7") alert(42);
Linting src/foo.js...ERROR
[L1:C14] W116: Expected '{' and instead saw 'alert'.
if(7 == "7") alert(42);

Warning: Task "jshint:target1" failed. Use --force to continue.

Aborted due to warnings.

The result shows that JSHint found two warnings in the src/foo.js file on:

  • Line 1, column 6—since we've enforced the use of strict equality, == is not allowed, so it must be changed to ===.

  • Line 1, column 14—since we've enforced the use of the curly braces, the if statement body must explicitly use curly braces.

Once we've fixed these two issues as follows:

if(7 === "7") {
  alert(42);
}

We can then re-run grunt and we should see:

$ grunt
Running "jshint:target1" (jshint) task
>> 2 files lint free.

Done, without errors.

Notice that two files were reported to be lint free. The second file was the Gruntfile.js file, and if we review this file, we see it does not break either of the two rules we enabled.

In summary, JSHint is very useful as the first step of our Grunt build as it can help catch simple errors, such as unused variables or accidental assignments in if statements. Also, by enforcing particular coding standards on the project's code base, it helps maintain code readability, as all code entering the shared repository will be normalized to a predetermined coding style.

Transcompilation

Transcompiling—also known as source-to-source compilation and often abbreviated to transpiling—is the process of converting the source code of one language to the source code of another. Within the web development community in recent years, there has been an increase in the use of transcompile languages such as Haml, Jade, Sass, LESS, Stylus, CoffeeScript, Dart, TypeScript, and more.

The idea of transcompiling has been around since the 1980s. A popular example was an original C++ compiler (Cfront) by Bjarne Stroustrup, which converted C++ (known as C with Classes at the time) to C.

CoffeeScript

CoffeeScript (http://gswg.io#coffeescript) is the most popular transpile language for JavaScript. It was released in 2009 by Jeremy Ashkenas and is now the 10th most popular language on GitHub with 3 percent of the all code in public Git repositories. Due to this popularity, a particularly common use case for the modern web developer is to compile CoffeeScript to JavaScript. This can be easily achieved with the Grunt plugin http://gswg.io#grunt-contrib-coffee.

In the following example, we'll use the grunt-contrib-coffee plugin to compile all of our CoffeeScript files:

//Code example 05-coffeescript
module.exports = function(grunt) {

  // Load the plugin that provides the "coffee" task.
  grunt.loadNpmTasks('grunt-contrib-coffee');

  // Project configuration.
  grunt.initConfig({
    coffee: {
      target1: {
        expand: true,
        flatten: true,
        cwd: 'src/',
        src: ['*.coffee'],
        dest: 'build/',
        ext: '.js'
      },
      target2: {
        files: {
          'build/bazz.js': 'src/*.coffee'
        }
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['coffee']);
};

Inside the configuration, the coffee object has two properties; each of which defines a target. For instance, we might wish to have one target to compile the application source and another target to compile the unit test source. We'll cover more on tasks, multitasks, and targets in Chapter 2, Setting Up Grunt.

In this case, the target1 target will compile each .coffee file in the src directory to a corresponding output file in the build directory. We can execute this target explicitly with grunt coffee:target1, which should produce the result:

$ grunt coffee:target1
Running "coffee:target1" (coffee) task
File build/bar.js created.
File build/foo.js created.

Done, without errors.

Next, target2 will compile and combine each of the .coffee files in the src directory to a single file in the build directory called bazz.js. We can execute this target with grunt coffee:target2, which should produce the result:

grunt coffee:target2
Running "coffee:target2" (coffee) task
File build/bazz.js created.

Done, without errors.

Combining multiple files into one has advantages and disadvantages, which we shall review in the next section Minification.

Jade

Jade (http://gswg.io#jade) compiles to HTML and, as with CoffeeScript to JavaScript, Jade has the semantics of HTML, though different syntax. TJ Holowaychuk, an extremely prolific open-source contributor, released Jade in July 2010. More information on the Grunt plugin for Jade can be found at http://gswg.io#grunt-contrib-jade.

We'll also notice the following example Gruntfile.js file is quite similar to the previous CoffeeScript example. As we will see with many Grunt plugins, both these examples define some kind of transform from one set of source files to another set of destination files:

//Code example 06-jade
module.exports = function(grunt) {

  // Load the plugin that provides the "jade" task.
  grunt.loadNpmTasks('grunt-contrib-jade');

  // Project configuration.
  grunt.initConfig({
    jade: {
      target1: {
        files: {
          "build/foo.html": "src/foo.jade",
          "build/bar.html": "src/bar.jade"
        } 
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['jade']);
};

In this example, target1 will do a one-to-one compilation, where src/foo.jade and src/bar.jade will be compiled into build/foo.html and build/bar.html respectively. As we have set the default task to be the jade task, we can run all of jade's targets with a simple grunt command, which should produce:

$ grunt
Running "jade:target1" (jade) task 
File "build/foo.html" created.
File "build/bar.html" created.

Done, without errors.
Stylus

Stylus (http://gswg.io#stylus) compiles to CSS, and as before, it has the semantics of CSS though different syntax. TJ Holowaychuk also created Stylus, which he officially released in February 2011. More information on the Stylus Grunt plugin can be found at http://gswg.io#grunt-contrib-stylus. Similarly to the examples above, the following example Gruntfile.js file contains only slight differences. Instead of jade, we're configuring stylus, and instead of transpiling .jade to .html, we're transpiling .styl to .css:

//Code example 07-stylus
module.exports = function(grunt) {

  // Load the plugin that provides the "stylus" task.
  grunt.loadNpmTasks('grunt-contrib-stylus');

  // Project configuration.
  grunt.initConfig({
    stylus: {
      target1: {
        files: {
          "build/foo.css": "src/foo.styl"
        }
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['stylus']);
};

When we run grunt, we should see the following:

$ grunt
Running "stylus:target1" (stylus) task
File build/foo.css created.

Done, without errors.
Haml, Sass, and LESS

Grunt plugins that transpile code are very similar, as previously seen with CoffeeScript, Jade and Stylus. In some way or another, they define a set of input files and a set of output files, and also provide options to vary the compilation. For the sake of brevity, I won't go through each one, but instead I'll provide links to each preprocessor (transcompiler tool) and its respective Grunt plugins:

  • Haml—http://gswg.io#haml—gswg.io#grunt-haml

  • Sass—http://gswg.io#sass—gswg.io#grunt-contrib-sass

  • LESS—http://gswg.io#less—gswg.io#grunt-contrib-less

At the end of the day, the purpose of using transcompile languages is to improve our development workflow, not to hinder it. If using these tools requires a lengthy setup for each, then the more tools we add to our belt, the longer it'll take our team to get up and running. With Grunt, we add each plugin to our package.json and with one npm install command, we have all the plugins we need and can start transpiling in minutes!

Minification


As web applications increase in complexity, they also increase in size. They contain more HTML, more CSS, more images, and more JavaScript. To provide some context, the uncompressed development version of the popular JavaScript library, jQuery (v1.9.1), has reached a whopping 292 KB. With the shift to mobile, our users are often on unreliable connections and loading this uncompressed jQuery file could easily take more than 5 seconds. This is only one file, however, often websites can be as large as 2-3MB causing load times to skyrocket. A blog post from KISSmetrics (http://gswg.io#loading-time-study) reveals the following, using data from gomez.com and akamai.com:

73% of mobile Internet users say they have encountered a website that was too slow to load.

51% of mobile Internet users say they have encountered a website that crashed, froze, or received an error.

38% of mobile Internet users say they have encountered a website that wasn't available.

47% of consumers expect a web page to load in 2 seconds or less.

40% of people abandon a website that takes more than 3 seconds to load.

A 1 second delay in page response can result in a 7% reduction in conversions.

If an e-commerce site is making $100,000 per day, a 1 second page delay could potentially cost you $2.5 million in lost sales every year.

Based on this information, it is clear we should do all we can to reduce page load times. However, manually minifying all of our assets is time consuming, so it is Grunt to the rescue! The Grunt team has plugins for the following common tasks:

In the following example Gruntfile.js, we see how easy this process is. Much like the compilation tasks above, these minification tasks are also a transformation, in that they have file inputs and file outputs. In this example, we'll utilize the grunt-contrib-uglify plugin, which will provide the uglify task:

  grunt.initConfig({
    uglify: {
      target1: {
        src: 'foo.js',
        dest: 'foo.min.js'
      }
    }
  });

This is only a portion of Code example 01-minify, the complete snippet can be found in the code examples (http://gswg.io#examples) or by returning to the start of this chapter. As with the uglify task, the cssmin and htmlmin tasks also have options to customize the way our code is compressed. See the corresponding GitHub project pages for more information.

Tip

If you're using Jade to construct your HTML, then you can use its built-in compression option by setting pretty to false.

Concatenation


As with minification, concatenation (or joining) also helps reduce page load time. As per the HTTP 1.1 specification, browsers can only request two files at once (see HTTP 1.1 Pipelining). Although newer browsers have broken this rule and will attempt to load up to six files at once, we will see it is still the cause of slower page load times.

For example, if we open Chrome Developer Tools inside Google Chrome, view the Network tab, then visit the cnn.com website, we see approximately 120 file requests, 40 of which are loading from the cnn.com domain. Hence, even with six files being loaded at once, our browsers still must wait until a slot opens up before they can start downloading the next set of files.

Also, if there are more files to load over a longer period of time, there will be a higher chance of TCP connection dropouts, resulting in even longer waits. This is due to the browser being forced to re-establish a connection with the server.

When building a large Web Application, JavaScript will be used heavily. Often, without the use of concatenation, developers decide not to segregate their code into discrete modular files, as they would then be required to enter a corresponding script tag in the HTML. If we know all of our files will be joined at build-time, we will be more liberal with creation of new files, which in turn will guide us toward a more logical separation of application scope.

Therefore, by concatenating assets of similar type together, we can reduce our asset count, thereby increasing our browser's asset loading capability.

Although concatenation was solved decades ago with the Unix command: cat, we won't use cat in this example, instead, we'll use the Grunt plugin: http://gswg.io#grunt-contrib-concat. This example Gruntfile.js file demonstrates use of the concat task, which we'll see is very similar to the tasks above as it is also a fairly simple transformation:

//Code example 08-concatenate
module.exports = function(grunt) {

  // Load the plugin that provides the "concat" task.
  grunt.loadNpmTasks('grunt-contrib-concat');

  // Project configuration.
  grunt.initConfig({
    concat: {
      target1: {
        files: {
          "build/abc.js": ["src/a.js", "src/b.js", "src/c.js"]
        }
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['concat']);
};

As usual, we will run it with grunt and should see the following:

$ grunt
Running "concat:target1" (concat) task
File "build/abc.js" created.

Done, without errors.

Just like that, our three source files have been combined into one, in the order we specified.

Deployment


Deployment is one of the lengthier tasks when it comes to releasing the final product. Generally, it involves logging into a remote server, manually finding the correct files to copy, restarting the server and praying we didn't forget anything. There may also be other steps involved which could further complicate this process, such as performing a backup of the current version or modifying a remote configuration file. Each one of these steps can be catered for with Grunt, either with plugins, which provide useful tasks, or with our own custom tasks where we may wield the complete power of Node.js.

As mentioned in the first section, we can use Grunt to script these types of processes, thus removing the element of human error. Human error is probably the most dangerous at the deployment step because it can easily result in server down time, which will often result in monetary losses.

In the following subsections, we'll cover three common methods of deploying files to our production servers: FTP, SFTP, and S3. We won't however, cover the creation of custom tasks and plugins in this section, as we will go through these topics in depth in Chapter 3, Using Grunt.

FTP

The File Transfer Protocol specification was released in 1980. Because of FTP's maturity and supremacy, FTP became the standard way to transfer files across the Internet. Since FTP operates over a TCP connection, and given the fact that Node.js excels in building fast network applications, an FTP client has been implemented in JavaScript in approximately 1000 lines, which is tiny! It can be found at http://gswg.io#jsftp.

A Grunt plugin has been made using this implementation, and this plugin can be found at http://gswg.io#grunt-ftp-deploy. In the following example, we'll use this plugin along with a local FTP server:

//Code example 09-ftp
module.exports = function(grunt) {

  // Load the plugin that provides the "ftp-deploy" task.
  grunt.loadNpmTasks('grunt-ftp-deploy');

  // Project configuration.
  grunt.initConfig({
    'ftp-deploy': {
      target1: {
        auth: {
          host: 'localhost',
          port: 21,
          authKey: 'my-key'
        },
        src: 'build',
        dest: 'build'
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['ftp-deploy']);
};

When the ftp-deploy task is run, it looks for an .ftppass file, which contains sets of usernames and passwords. When placing a Grunt environment inside a version control system, we must be wary of unauthorized access to login credentials. Therefore, it is good practice to place these credentials in an external file, which is not under version control. We could also use system environment variables to achieve the same effect.

Our Gruntfile.js above has set the key option to "my-key", this tells ftp-deploy to look for this property inside our .ftppass file (which is in JSON format). So, we should create a .ftppass file like:

{
  "my-key": {
    "username": "john",
    "password": "smith"
  }
}

Tip

For testing purposes, there are free FTP servers available: PureFTPd http://gswg.io#pureftpd (Mac OS X) and FileZilla Server http://gswg.io#filezilla-server (Windows).

Once we have an FTP server ready, with the correct username and password, we are ready to transfer. Running this example should produce the following:

$ grunt
Running "ftp-deploy:target1" (ftp-deploy) task
>> New remote folder created /build/
>> Uploaded file: foo.js to: /
>> FTP upload done!

FTP is widespread and commonly supported; however, as technology and software improve, as legacy systems get deprecated, and as data encryption becomes a negligible computational cost, the use of unencrypted protocols like FTP is in decline—which segues us to SFTP.

SFTP

The Secure File Transfer Protocol is often incorrectly assumed to be a normal FTP connection tunneled through an SSH (Secure Shell) connection. However, SFTP is a new file transfer protocol (though it does use SSH).

In this example, we are copying three HTML files from our local build directory to the remote tmp directory. Again, to avoid placing credentials inside build, we store our username and password inside our credentials.json file. This example uses the Grunt plugin http://gswg.io#grunt-ssh. This plugin actually provides two tasks: sftp and sshexec, however, in this example we'll only be using the sftp task:

//Code example 10-sftp
module.exports = function(grunt) {

  // Load the plugin that provides the "sftp" task.
  grunt.loadNpmTasks('grunt-ssh');

  // Project configuration.
  grunt.initConfig({
    
    credentials: grunt.file.readJSON('credentials.json'),

    sftp: {
      options: {
        host: 'localhost',
        username: '<%= credentials.username %>',
        password: '<%= credentials.password %>',
        path: '/tmp/',
        srcBasePath: 'build/'
      },
      target1: {
        src: 'build/{foo,bar,bazz}.html'
      }
    }
  });

  // Define the default task
  grunt.registerTask('default', ['sftp']);
};

At the top of our configuration, we created a new credentials property to store the result of reading our credentials.json file. Using Grunt templates, which we cover in Chapter 2, Setting Up Grunt, we can list the path to the property we wish to substitute in. Once we have prepared our credentials.json file, we can execute grunt:

$ grunt
Running "sftp:target1" (sftp) task

Done, without errors.

We notice the sftp task didn't display any detailed information. However, if we run Grunt with the verbose flag: grunt -v we should see this snippet at the end of our output:

Connection :: connect
copying build/bar.html to /tmp/bar.html
copied build/bar.html to /tmp/bar.html
copying build/bazz.html to /tmp/bazz.html
copied build/bazz.html to /tmp/bazz.html
copying build/foo.html to /tmp/foo.html
copied build/foo.html to /tmp/foo.html
Connection :: end
Connection :: close

Done, without errors.

This output clearly conveys that we have indeed successfully copied our three HTML files from our local directory to the remote directory.

S3

Amazon Web Service's Simple Storage Service is not a deployment method (or protocol) like FTP and SFTP, but rather a service. Nevertheless, from a deployment perspective they are quite similar as they all require some configuration, including destination and authentication information.

Hosting Web Applications in the Amazon Cloud has grown quite popular in recent years. The relatively low prices of S3 make it a good choice for static file hosting, especially as running your own servers can introduce many unexpected costs. AWS has released a Node.js client library for many of its services. Since there was no Grunt plugins utilizing this library at the time, I decided to make one. So, in the following example, we are using http://gswg.io#grunt-aws. Below, we are attempting to upload all of the files inside the build directory into the root of the chosen bucket:

  //Code example 11-aws
  grunt.initConfig({
    aws: grunt.file.readJSON("credentials.json"),
    s3: {
      options: {
        accessKeyId: "<%= aws.accessKeyId %>",
        secretAccessKey: "<%= aws.secretAccessKey %>",
        bucket: "..."
      },
      //upload all files within build/ to output/
      build: {
        cwd: "build/",
        src: "**"
      }
    }
  });

Again, similar to the SFTP, we are using an external credentials.json file to house our valuable information. So, before we can run this example, we first need to create a credentials.json file, which looks like:

{
  "accessKeyId": "AKIAIMK...",
  "secretAccessKey": "bt5ozy7nP9Fl9..."
}

Next, we set the bucket option to the name of bucket we wish to upload to, then we can go ahead and execute grunt:

$ grunt
Running "s3:build" (s3) task
Retrieving list of existing objects...
>> Put 'foo.html'
>> Put 'bar.js'
>> Put 2 files

Done, without errors.

Summary


In this chapter, we have learnt Grunt is an easy to use JavaScript build tool, which has the potential to greatly improve the development cycle of the typical front-end developer. We have covered many common build problems in this chapter and, by combining these examples, we see we can quite easily make use of various premade Grunt plugins to vastly simplify previously complex build processes.

In the next chapter, we will review the steps required to install Grunt and its only dependency—Node.js, and also the various methods of configuring Grunt.

Left arrow icon Right arrow icon

What you will learn

  • Learn about Grunt and its advantages
  • Understand Node.js and how it relates to Grunt
  • Take an indepth look at npm, Node.js modules, and the working of Grunt plugins
  • Get familiar with installing Grunt and setting up your first Grunt build environment
  • Gain insight on the methods of configuring Grunt and when each method should be used
  • Effectively execute Grunt through the use of task arguments, task aliasing, multitask targets, and more
  • Construct your own Grunt tasks, multitasks, and asynchronous tasks
Estimated delivery fee Deliver to Colombia

Standard delivery 10 - 13 business days

$19.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Feb 19, 2014
Length: 132 pages
Edition :
Language : English
ISBN-13 : 9781783980628
Category :
Languages :
Tools :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
OR
Modal Close icon
Payment Processing...
tick Completed

Shipping Address

Billing Address

Shipping Methods
Estimated delivery fee Deliver to Colombia

Standard delivery 10 - 13 business days

$19.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Publication date : Feb 19, 2014
Length: 132 pages
Edition :
Language : English
ISBN-13 : 9781783980628
Category :
Languages :
Tools :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 148.97
Getting Started with Grunt: The JavaScript Task Runner
$38.99
Node Cookbook: Second Edition
$54.99
Mastering Node.js
$54.99
Total $ 148.97 Stars icon

Table of Contents

5 Chapters
Introducing Grunt Chevron down icon Chevron up icon
Setting Up Grunt Chevron down icon Chevron up icon
Using Grunt Chevron down icon Chevron up icon
Grunt in Action Chevron down icon Chevron up icon
Advanced Grunt Chevron down icon Chevron up icon

Customer reviews

Top Reviews
Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.4
(10 Ratings)
5 star 50%
4 star 40%
3 star 10%
2 star 0%
1 star 0%
Filter icon Filter
Top Reviews

Filter reviews by




Willie Pritchett Apr 09, 2014
Full star icon Full star icon Full star icon Full star icon Full star icon 5
While the book's title would lead you to believe that the book is about Grunt, which it is for the most part, you are also treated with the added bonus of receiving a slight introduction into Node.JS as well!As a full stack developer, I can appreciate tools that assist in making my job easier and Grunt is an exceptional tool for eliminating repetitive tasks and this book covers it beautifully. Some topics that you will gain helpful insight on include:1. Configuring Grunt to run your own Tasks2. Using Grunt for Testing purposes3. Setting up and Configuring GruntI would say this book is moreso for a user who has a working knowledge of Javascript or at least a beginner Javascript developer. Otherwise, many of the terms used throughout the book will not make much sense.An Excellent read and I highly recommend it.
Amazon Verified review Amazon
Hemanta Sapkota Mar 31, 2014
Full star icon Full star icon Full star icon Full star icon Full star icon 5
The book maybe about Grunt, but its biggest value proposition, IMHO, is the excellent walkthrough on the Node.js ecosystem and modern web development.The author has very cleverly leveraged Grunt as a medium to introduce more advanced tools like Coffeescript, Jade, Stylus, all of which when used properly results in a huge productivity boost. See Chapter 4 Grunt in Action.The only thing that I felt missing was a chapter on Javascript itself. A brief intro on Javascript and its idiosyncrasies could have served as a nice appendix. Although, the book does contain a good reference list on Javascript.Who will benefit from the book ? Not including the usual front-end developers and framework creators:1. Experienced Java developers like myself who've made the move to the dynamic world of Javascript (front-end/backend)2. Web developers proficient in JQuery/PHP but have failed to get onboard the Node trainAll in all, there's no doubt that the book will serve as a handy reference for Javascript developers.
Amazon Verified review Amazon
Callie Jul 03, 2014
Full star icon Full star icon Full star icon Full star icon Full star icon 5
I'm a newbie to web development, and I've been doing A LOT of reading over the last two months. This book was well written and informative. I would recommend this book to anyone who is trying to teach themselves Grunt.
Amazon Verified review Amazon
astericky Jul 29, 2014
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book is among the best introductions to Grunt: The Javascript Task Runner and Nodejs platform I have seen to date. I was so pleased with this book that I recommended it to the other developers on my team immediately upon finishing this book.The author immediately starts us out with creating a simple Grunt task. He explains the benefits of using a task runner at all in the development process. We learn why Grunt is an excellent choice for task runner in real world use cases such as code minification, code linting and code deployments.Next we are guided through a more thorough set up of Grunt and the NodeJS platform. We learn about basic configuration and directory structure. The author does not stop there though. He walks us through installing grunt packages and plug-ins as well as building our own custom Grunt tastsk.By the end of this book the author had me convinced that Grunt is the tool my team can leaverage at work to get control of our unweildy code base and get some structure and consistency around our deployment process.Often times I find that beginner books are almost too beginner for the audience they are trying to target. This book really hits the sweetspot in terms of getting beginners set up quickly and easily without alienating more senior developers or going into the gory details of Grunt before developers have any real context or understanding around the problem Grunt attempts to solve.One way I would improve this book is move the last 15-20 pages on development tools to an appendix of some sort. However, I would not include it as a part of a chapter titled Advanced Grunt.Full disclosure: I was asked to do this review literally the day after I finished it. However, I've read this book and thoroughly enjoyed every minute of it.I'm stunned that such a potentially boring topic could make for an amazing book.Full disclosure: I was asked to do this review literally the day after I finished it. However, I've read this book and thoroughly enjoyed every minute of it.
Amazon Verified review Amazon
P S Sep 17, 2015
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book is worth every cent! Not only it gives you information on grunt but background on node js is just fantastic.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela