> For the complete documentation index, see [llms.txt](https://cedrus.gitbook.io/codesoju/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://cedrus.gitbook.io/codesoju/task_automation_manager.md).

# Task Automation Manager

## Why Task Automation?

Task automation allows for a more efficient development workflow.

Rather than having to manually execute repetitive tasks, developers can use task automation managers and a myriad of community plugins that are easy to learn and use.

## Grunt vs. Gulp

Currently the two most prominent task automation managers are [Grunt](http://gruntjs.com/) and [Gulp](http://gulpjs.com/). While both achieve the same goal, they take different paths to get there.

|                                                                             | Grunt                    | Gulp                         |
| --------------------------------------------------------------------------- | ------------------------ | ---------------------------- |
| [**Task Setup**](/codesoju/task_automation_manager.md#1-task-setup)         | Configuration-based      | Code over configuration      |
| [**Task Execution**](/codesoju/task_automation_manager.md#2-task-execution) | Runs tasks synchronously | Can run tasks asynchronously |
| [**I/O**](/codesoju/task_automation_manager.md#3-io)                        | Creates Temporary Files  | Streams                      |
| [**Error Handling**](/codesoju/task_automation_manager.md#4-error-handling) | Standard                 | Poor                         |
| [**Community**](/codesoju/task_automation_manager.md#5-community)           | Larger community         | Growing community            |

For the examples below, this is the sample project directory structure: ![](https://4003200735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LJEac1z_W4FEYD64X-0%2F-LJEagJzqvIYySJlvQaF%2F-LJEanyMOO5-2XYB6qH5%2Fcode_soju_sample_directory.png?generation=1533565169033982\&alt=media)

### 1. Task Setup

Code over configuration refers to the style in which Gulpfiles are written. Gruntfiles consist mainly of a configuration object and task definitions. Gulpfiles look more like code written in Node.js.

To see the main difference in task setup, let's look at an example.

We're going to create a task that concatenates and minifies all Javascript files.

**Gruntfile.js**

```javascript
module.exports = function(grunt) {

  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    concat: {
      dist: {
        src: ['client/app/app.js', 'client/app/**/*.js'],
        dest: 'client/dist/scripts.js'
      }
    },
    uglify: {
      options: {
        compress: true,
        mangle: true
      },
      my_target: {
        files: {
          'client/dist/scripts.js': 'client/dist/scripts.js'
        }
      }
    }
  });

  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');

  grunt.registerTask('default', ['concat', 'uglify']);
}
```

1. Grunt requires configuring the different plugins in the object passed into the `grunt.initConfig(configObject)` method.
2. Then the plugins need to be loaded individually in the `grunt.loadNpmTasks(nameOfPlugin)` method.

   > This plugin will load all Grunt NPM tasks at once: [load-grunt-tasks](https://github.com/sindresorhus/load-grunt-tasks)
3. Finally, tasks must be registered by using the `grunt.registerTask(nameOfTask, [taskOne, taskTwo])` method. In the example above, we registered a default task so just running `grunt` will execute the 'concat' and 'uglify' tasks.

**Gulpfile.js**

```javascript
var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');

gulp.task('buildJS', function() {
  return gulp.src('client/app/**/*.js')
    .pipe(concat('scripts.js'))
    .pipe(uglify())
    .pipe(gulp.dest('client/dist/'));
});

gulp.task('default', ['buildJS']);
```

1. Gulp requires loading the plugins by using the native NodeJS `require(nameOfPlugin)` function.
2. Gulp tasks are registered using the `gulp.task(nameOfTask, callbackFn)` method.
   * If the `callbackFn` accepts another callback as a parameter or returns either a stream or a promise, the tasks can be run asynchronously. In the example above, the `callbackFn` returns a stream.&#x20;
   * `gulp.src(globs)` specifies the source files we want to run the tasks on. The [globs](https://github.com/isaacs/node-glob) parameter can be a string or an array of strings. This method allows us to pipe files matching the glob(s) to plugins.
   * The first plugin concatenates all the files matched by the glob into one `scripts.js` file.
   * The `scripts.js` file is then piped into the uglify plugin which will minify the contents of the file.&#x20;
   * Finally, the concatenated and minified file is piped into the `client/dist/` directory using the `gulp.dest(directoryPath)` method.
3. You set the buildJS task as the default task and run the `gulp` command or you can call run the buildJS task directly by running `gulp buildJS`.

The Gulpfile is more concise than the Gruntfile. In larger projects with more tasks, a giant Grunt configuration object may be confusing to navigate.

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)

### 2. Task Execution

Grunt runs tasks in sequence while Gulp will run tasks with maximum concurrency.

For example, if you wanted to run these tasks:

1. Concatentate all Javascript files
2. Minify the concatentated script file
3. Compile SASS to CSS
4. Watch all CSS and JS files for changes

the Grunt task would look like this:

```javascript
grunt.registerTask('buildApp', ['concat', 'uglify', 'sass', 'watch']);
```

where each task would run after the preceding task is complete. This ensures that the defined task sequence is the sequence in which the tasks will execute.

Gulp uses a module called [orchestrator](https://github.com/robrich/orchestrator) for sequencing with maximum concurrency. What orchestrator will do is launch all the tasks specified at the same time. So if you were to mimic the Grunt task above:

```javascript
gulp.task('buildApp', ['concat', 'uglify', 'sass', 'watch']);
```

the order that the tasks complete isn't guaranteed because all tasks will start at once. The `uglify` task might complete before the `concat` task.

Gulp does provide a way to execute tasks in a specified sequence using dependencies in tasks.

In the example above, to run all tasks in the desired sequence, specify the preceding task as a dependency as the second parameter when defining a task.

```javascript
gulp.task('concat', ...);

// this task is dependent on the `concat` task completing
gulp.task('uglify', ['concat'], ...);

// this task is dependent on the `uglify` task completing
gulp.task('sass', ['uglify'], ...);

// this task is dependent on the `sass` task completing
gulp.task('watch', ['sass'], ...);
```

> Note: The example above is just to demonstrate how Gulp works. It would be much more common to have the `concat` and `uglify` tasks defined in a single task, where the output of `concat` would be piped to `uglify`.

Running `gulp watch` will run the `concat` task, then the `uglify` task, then the `sass` task, and finally the `watch` task.

However, the above example does not utilize the benefits of maximum concurrency. Total time to complete all tasks will be shortened if unrelated tasks run at the same time, rather than sequentially.

The example above can be re-written like so:

```javascript
gulp.task('concat', ...);

// this task is dependent on the `concat` task completing
gulp.task('uglify', ['concat'], ...);

gulp.task('sass', ...);

// this task is dependent on the `sass` task and the 'uglify' task completing
gulp.task('watch', ['sass', 'uglify'], ...);
```

Now running `gulp watch` will launch both the `sass` and `uglify` tasks at the same time. Since the compilation of SASS to CSS is not related to the minification of Javascript files, it is okay to start these tasks streams concurrently for faster execution time.

> Note: 1. The [next version of Grunt](https://github.com/gruntjs/grunt-next) will also use the orchestrator module so the speed advantage that Gulp offers might be offset. 2. To replace the somewhat convoluted sequencing through dependencies, the [next version of Gulp](https://github.com/gulpjs/gulp/blob/4.0/CHANGELOG.md) will use the [undertaker](https://github.com/gulpjs/undertaker) module which will allow you to specify whether you want to run tasks in sequence (`gulp.series`) or in parallel (`gulp.parallel`).

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)

### 3. I/O

One of Gulp's distinguishing features is it's usage of Node.js streams.

With Grunt, each task needs to read the relevant files, transform the contents, and write the results to a temporary folder, so that the next task is able to repeat this process. The problem with this is that opening and closing files and creating a temporary folder are "expensive" operations.

Streams allow for the output of a task to be piped to the input of the next task. This is accomplished in Gulp by using [vinyl](https://github.com/gulpjs/vinyl) and [vinyl-fs](https://github.com/gulpjs/vinyl-fs).

According to the documentation, "[Vinyl is a very simple metadata object that describes a file.](https://github.com/gulpjs/vinyl-fs#what-is-vinyl)" Along with the vinyl-fs adapter, this allows for transformations to happen on the vinyl object which is all done in memory.

> **Note**: If this is at all confusing, you've run into one of the cons of Gulp. Gulp does require some understanding of streams and if you come from a non-Node.js background, this may be another concept you have to learn.

What does this mean for performance?

| Grunt                                                                                                                                                                                                            |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![](https://4003200735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LJEac1z_W4FEYD64X-0%2F-LJEagJzqvIYySJlvQaF%2F-LJEanySs_xxt6Ntk7pP%2Fgrunt_time.png?generation=1533565167706250\&alt=media) |

| Gulp                                                                                                                                                                                                            |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| ![](https://4003200735-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LJEac1z_W4FEYD64X-0%2F-LJEagJzqvIYySJlvQaF%2F-LJEanyUDSKyPTT7YOBT%2Fgulp_time.png?generation=1533565169508841\&alt=media) |

Grunt took **207 ms** to complete and Gulp took a little over **73 ms**.

When dealing in milliseconds, this difference may seem negligible, but when working with larger projects and more tasks, the difference may grow.

> Note: These results should be taken with a grain of salt because the way both task runners measure time may be slightly different. However, in researching this topic, it seems that other developers have seen similar outcomes. I've included those articles in the [**Additional Reading**](/codesoju/task_automation_manager.md#additional-reading) section in bold.

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)

### 4. Error Handling

Error handling is probably Gulp's biggest weakness.

Node.js streams will stop working upon encountering an error. For certain tasks such as linting, this is undesirable because you would want the entirety of the source code to have been run through the linting task. If an error occurs somewhere in the first half of the files passed through the task, the process will exit and the second half would never have been "linted."

There is currently a [monkey patch](https://github.com/floatdrop/gulp-plumber) that modifies the `pipe` function to not exit upon erroring.

One of the [creators of Gulp has admitted that this is an issue](https://medium.com/@contrahacks/gulp-3828e8126466#.q9cw804vd) which will be addressed in the next major release.

Grunt doesn't use streams and has a more reliable [fail API](http://gruntjs.com/api/grunt.fail) for error handling. It provides options such as `--force` to continue the task and `--stack` to output a stacktrace.

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)

### 5. Community

> "There are three kinds of lies: lies, damned lies and statistics." - Mark Twain

Grunt's community may be its biggest strength. It is the older of the two and as of June 2016, Grunt has **5,759** plugins compared to Gulp's **2,458**. This is not an insignificant difference.

With that in mind, recent trends may show that Gulp is on the rise.

> Note: Statistics can be deceptive. For example, if Gulp had more downloads than Grunt the past month, that may be more indicative of Grunt's market saturation rather than Gulp's popularity. Stats over a shorter period of time are even less reliable. I will just present the numbers and you may decide if they are significant in your decision.

| npm                         | Grunt      | Gulp       |
| --------------------------- | ---------- | ---------- |
| Downloads in the last day   | 22,863     | 85,940     |
| Downloads in the last week  | 436,006    | 518,959    |
| Downloads in the last month | 1,774,681  | 2,224,780  |
| Total downloads             | 34,466,022 | 28,149,784 |

> Note: Grunt's statistics start from it's release in 11/2012 to 06/2016. Gulp's statistics start from it's release in 07/2013 to 06/2016.

| GitHub | Grunt  | Gulp   |
| ------ | ------ | ------ |
| Watch  | 618    | 1,029  |
| Star   | 10,853 | 21,583 |
| Fork   | 1,366  | 2,784  |

> Note: **Watching** a repository means all pull requests and issues will be show up in the news feed. **Starring** a repository is meant to track and show appreciation for a project without receiving activity notifications. **Forking** a repository copies a project and suggested changes to the original project can be made via a pull request.

| stackoverflow                                    | Grunt | Gulp  |
| ------------------------------------------------ | ----- | ----- |
| Tags                                             | 8,018 | 6,534 |
| Questions asked today (6/14/2016)                | 6     | 11    |
| Questions asked this week (6/7/2016 - 6/14/2016) | 34    | 82    |

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)

## Conclusion

In the end, choosing a task runner comes down to personal preference. If you are more familiar with Grunt or if the majority of your team knows Grunt but not Gulp, it might not make sense to make the switch.

However, we at CodeSoju, in our attempt to outline best practices in creating enterprise applications, are of the opinion that the benefits of Gulp outweigh the benefits of Grunt. The more readable task configurations, increased performance benefits, and a growing community are why we recommend Gulp for your task automation needs.

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)

## Additional Reading

#### Comparisons

> Articles in bold contain speed comparisons.

1. [**Six Revisions: Grunt vs Gulp**](http://sixrevisions.com/web-development/grunt-vs-gulp/)
2. [**Velocity Partners: Grunt vs Gulp for Javascript Task Automation**](http://www.velocitypartners.net/blog/2016/02/19/gulp-vs-grunt-for-javascript-task-automation/)
3. [**Grunt vs Gulp: Beyond the Numbers**](http://jaysoo.ca/2014/01/27/gruntjs-vs-gulpjs/)
4. [Grunt, Gulp, Whatever](https://ponyfoo.com/articles/gulp-grunt-whatever#the-boar-is-becoming-kind-of-stale)

#### Grunt

1. [Grunt Official Site](http://gruntjs.com/)
2. [Get Up And Running With Grunt](https://www.smashingmagazine.com/2013/10/get-up-running-grunt/)
3. [Grunt for People Who Think Things Like Grunt are Weird and Hard](https://24ways.org/2013/grunt-is-not-weird-and-hard/)
4. [Supercharging your Gruntfile: How to squeeze the most out of your build configuration.](http://www.html5rocks.com/en/tutorials/tooling/supercharging-your-gruntfile/)

#### Gulp

1. [Gulp Official Site](http://gulpjs.com/)
2. [gulp: The vision, history, and future of the project](https://medium.com/@contrahacks/gulp-3828e8126466#.q9cw804vd)
3. [Getting gulpy: Advanced tips for using gulp.js](https://medium.com/@webprolific/getting-gulpy-a2010c13d3d5#.di7z0h2i5)

   **Gulp Error Handling**

   * [Error management in gulp](https://gist.github.com/floatdrop/8269868)
   * [Building with Gulp: Caveats](http://blog.reactandbethankful.com/posts/2015/05/05/building-with-gulp-part-5-caveats/)
   * [gulp-plumber](https://github.com/floatdrop/gulp-plumber)
   * [Handling errors with gulp watch and gulp-plumber](http://blog.ibangspacebar.com/handling-errors-with-gulp-watch-and-gulp-plumber/)

\
&#x20;[**Back to top**](/codesoju/task_automation_manager.md#grunt-vs-gulp)
