Tuesday, March 19, 2024

Using JavaScript Task Runners

New Technology Based on an Old Idea

Back when I was in school during the early days of Windows, I learned about a neat application feature called a macro. They allow(ed) you to automate a number of operations so that you could execute at the click of a button. For example, I wrote one for MS Outlook that sends my articles to my editor. It took some time to set up, but now it saves me several minutes every time I email an article. So what happens when you need to combine several applications? In my school days there was something called the Component Object Model (COM), which allowed an application to interact with another via code. Outside of specific applications, there was DOS batch files, shell or bash scripts, and later, PowerShell.

Today’s Popular Task Runners

Released in May of 2009, Node.js was a JavaScript runtime-environment capable of operating independently from the browser. This was a crucial milestone for JavaScript as Node.js was the catalyst that made it possible to create processing tasks for front-end JavaScript that were previously impossible. Several different tasks runners were developed shortly thereafter. The first of these, Jake, was created in 2010. Jake was soon followed by Grunt, Brunch, Mimosa, Gulp, Broccoli, and Yarn, to name but a few.

Grunt is considered to be the first “second generation” task runner to arrive on the scene. It’s relative longevity has provided ample time to amass a large database of plugins. However, Gulp has grown to become the most popular and widely supported system at the present time. Despite having been developed in parallel with Gulp, the third place Task Runner, Broccoli, has failed to keep up. The smaller number of tasks available to Broccoli may be a contributing factor.

Setting up Your Project

While each Task Runner differs both in terms of philosophy and in its method of writing tasks, there are some similarities. For instance, a typical Task Runner setup will involve adding two files to your project: package.json and the task file.

  1. package.json: This file is used by the Task Runner to store metadata for projects published as npm modules. You will list plugins your project needs as Dependencies and “devDependencies” in this file.
  2. task file: This is a .js or .coffee file that is used to configure or define tasks and load plugins.

Here’s are some simple package.json files for Grunt, Gulp, and Broccoli, respectively:

//Grunt
{
  "name": "My Grunt Project",
  "version": "0.1.0",
  }, 
  "scripts": { 
    "test": "grunt qunit" 
  }, 
  "devDependencies": {
    "grunt": "~0.4.5",
    "grunt-contrib-jshint": "~0.10.0",
    "grunt-contrib-nodeunit": "~0.4.1",
    "grunt-contrib-uglify": "~0.5.0"
  }
}

//Gulp
{ 
     "name": "My Gulp Project", 
     "version": "0.0.1", 
     "private": true, 
     "scripts": { 
         "start": "node app" 
     }, 
     "dependencies": { 
         "express": "3.1.0", 
         "jade": "*" 
     }, 
     "devDependencies": { 
         "gulp": "*", 
         "gulp-coffee": "*", 
         "gulp-rename": "*", 
         "gulp-less": "*", 
         "gulp-uglify": "*", 
         "gulp-clean": "*", 
         "gulp-csso": "*" 
     } 
} 

//Broccoli
{ 
   "name": "My Broccoli Project", 
   "version": "0.0.0", 
   "description": "", 
   "main": "Brocfile.js", 
   "scripts": { 
   "test": "echo "Error: no test specified" && exit 1" 
  }, 
   "author": "", 
   "license": "ISC", 
   "devDependencies": { 
     "broccoli": "^0.13.3", 
     "broccoli-6to5-transpiler": "^3.0.0", 
     "broccoli-coffee": "^0.4.0", 
     "broccoli-concat": "0.0.12", 
     "broccoli-merge-trees": "^0.2.1", 
     "broccoli-sass": "^0.3.3", 
     "broccoli-traceur": "^0.12.0", 
     "gulp": "^3.8.11", 
     "gulp-coffee": "^2.3.1", 
     "gulp-concat": "^2.4.3", 
     "gulp-ruby-sass": "^1.0.0-alpha.3", 
     "lodash-node": "^3.2.0" 
   } 
} 

devDependencies vs. Dependencies

In the three package.json files above, you can see some dependencies and something called “devDependencies.” To clarify the difference between the two, dependencies are resources that are required to run, whereas devDependencies are only required to develop, e.g.: unit tests, CoffeeScript to JavaScript transpilation, minification, etc… The devDependencies object is for those resources that another developer probably wouldn’t want or need. For instance, if someone was planning on downloading and using your module in their program, then they likely wouldn’t want to download and build the external test or documentation framework that you use.

Configuring Tasks

Tasks are defined in a special .js or .coffee file. It’s usually named according to the system, i.e.: Gruntfile.js, gulpfile.js, and Brocfile.js respectively.

// Gruntfile.js
module.exports = function(grunt) {
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-uglify');

  grunt.initConfig({
    concat: {
      scripts: {
        src: ['src/**/*.js'],
        dest: 'temp/all.js'
      }
    },
    uglify: {
      scripts: {
        src: 'temp/all.js',
        dest: 'build/all.js'
      }
    },
  });

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

// gulpfile.js
var gulp   = require('gulp');
var uglify = require('gulp-uglify');
var concat = require('gulp-concat');

gulp.task('default', function() {
  return gulp
         .src('src/**/*.js')
         .pipe(concat('all.js'))
         .pipe(uglify())
         .pipe(gulp.dest('build/'));
});

//Brocfile.js
var babel  = require('broccoli-babel-transpiler')
var funnel = require('broccoli-funnel')
var concat = require('broccoli-concat')

var appJs = babel('src')

// Concatenate all the JS files into a single file
appJs = concat(appJs, {
  inputFiles: ['*.js'],
  outputFile: 'index.js'
})

module.exports = appJs

Conclusion

Now that we’ve covered what goes into adding a Task Runner to your Web project, we’ll move into specifics of how to work with individual Task Runners.

Rob Gravelle
Rob Gravelle
Rob Gravelle resides in Ottawa, Canada, and has been an IT guru for over 20 years. In that time, Rob has built systems for intelligence-related organizations such as Canada Border Services and various commercial businesses. In his spare time, Rob has become an accomplished music artist with several CDs and digital releases to his credit.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Popular Articles

Featured