Improving Your Ember.js Workflow Using Gulp.js

Lamin Sanneh
Share

I am a big advocate of the Ember.js framework. I have seen a lot of Ember tutorials on the web, but most do not explain how to setup a build system to use with it. In light of that, I have decided to take it upon myself to explain that part of the worflow. Since its arrival, Gulp.js has become a hot topic in the discussion of JavaScript task runners. It is no coincidence that Gulp.js pops up in the discussion when a JavaScript project is mentioned. So, this article is going to show how Gulp can be used with Ember projects.

I will be making some assumptions in this article. I assume that you already have a basic understanding of how Gulp.js works and that you have setup a Gulp.js project on your own before. If not, please visit SitePoint’s Introduction to Gulp.js for a refresher. The rest of this article will teach you how to create and configure common Gulp.js tasks with your Ember project.

A Typical Ember.js Workflow

I have worked on several Ember.js projects and I noticed that there are common requirements among them. These requirements involve the need to manipulate SCSS, CSS, JavaScript, and Handlebars code. Below are the requirements and a brief explanation of each.

SCSS Compilation

This involves the conversion of SCSS code into CSS.

JavaScript and CSS Minification

Minification is the process of reducing the size of a file by removing unnecessary white space. With CSS, this is usually done after converting SCSS code to CSS.

JavaScript and CSS Concatenation

Concatenation is the process of combining many files into one file. This is usually done to reduce the number of HTTP requests to a server. More files means more HTTP requests, which leads to longer download times. When concatenated, you need just one HTTP request. This is especially useful when serving files over a slow network connection, such as a mobile device.

File/Folder Watching

Tasks like minification, concatenation, and compilation can run be manually. However, they are repetitive tasks that quickly become tiresome and boring. Using the Gulp.js watcher task, you can setup a file watcher to watch your desired files for changes. When it detects a change, it will run one or more tasks in response to that change.

Handlebars Compilation

Handlebars is the default templating language of Ember.js. However, browsers cannot parse Handlebars code. Therefore, we need a way to convert Handlebars code to HTML. That’s where Handlebars compilation comes into action. First, the Handlebars code gets converted into a JavaScript function. Then, the function gets run when required by the Ember runtime to append the proper HTML to the DOM.

JavaScript Uglifying

Uglifying JavaScript is a two step process. The first step is removing whitespace through minification. The second step reduces JavaScript function names and variables into single characters where possible. The reasoning is that shorter variable names require fewer bytes, leading to faster downloads.

Gulp.js Plugins Breakdown

This section will highlight the plugins we will need and describe their functionality.

gulp

This is the base plugin which installs Gulp.js itself.

gulp-compass

This plugin compiles SCSS code into CSS. To use it, you must install Ruby and the compass gem.

gulp-uglify

This plugin uglifies JavaScript code. You can set an option not to change function names in case you hit some issues.

gulp-watch

This plugin enables you to have your project watch one or more files for changes.

gulp-concat

This plugin enables you to combine several CSS or JavaScript files into one. The files have to be the same type of course.

gulp-ember-handlebars

This plugin lets you convert Handlebars into JavaScript.

Installing the Plugins

First create a package.json file containing an empty JavaScript object, {}. Next, we’ll install the previously listed plugins. Using you terminal, navigate to the root directory of your project. Install and add the above plugins as dependencies by using the following commands in your terminal.

npm install gulp -g

This installs gulp globally. Next, save the plugin to your local project using this command:

npm install gulp --save-dev

The --save-dev part of the command adds the plugins as dependencies to your package.json. Removing it would only install the plugin but would not add it to your file.

Repeat the second command for the other plugins. In each case, replace gulp with the name of the plugin you wish to install. For example, gulp-compass, gulp-concat, etc. After doing that, take a look at your package.json, and you should see something like this:

{
  "devDependencies": {
    "gulp": "^3.8.0",
    "gulp-compass": "^1.1.9",
    "gulp-concat": "^2.2.0",
    "gulp-ember-handlebars": "^0.6.0",
    "gulp-uglify": "^0.3.0",
    "gulp-watch": "^0.6.5"
  }
}

Requiring the Plugins

Create a gulpfile.js in the same directory as your package.json. Inside it, add the following code, which imports the plugins. Looking at the variable names should be a good indicator of which plugin they represent.

var gulp = require('gulp'),
  compass = require('gulp-compass'),
  watch = require('gulp-watch'),
  handlebars = require('gulp-ember-handlebars'),
  uglify = require('gulp-uglify'),
  concat = require('gulp-concat');

Configuring Tasks for the Plugins

In this section, we will configure tasks by making use of the plugins in various combinations. Where applicable, I will state whether a task is utilizing more than one plugin. Note that all the file paths for the different tasks are relative to the gulpfile.js file.

CSS Task

This task accomplishes three things. It utilizes three plugins, compass, concat, and gulp. It compiles SCSS files into CSS, concatenates them, and outputs the result into a file of your choice.

gulp.task('css', function() {
  return gulp.src('scss/*.scss')
    .pipe(compass({ sass: 'scss' }))
    .pipe(concat('main.min.css'))
    .pipe(gulp.dest('dist/css'));
});

Templates Task

This task uses the handlebars, concat, and gulp plugins to accomplish two things. It takes a list of Handlebars files as input, compiles them into JavaScript, and concatenates them into one file. Then, it stores the output file into your desired location.

gulp.task('templates', function() {
  gulp.src(['js/templates/**/*.hbs'])
    .pipe(handlebars({
      outputType: 'browser',
      namespace: 'Ember.TEMPLATES'
    }))
    .pipe(concat('templates.js'))
    .pipe(gulp.dest('js/'));
});

Scripts Task

This task does two things and utilizes three plugins, gulp, concat, and uglify. It takes a list of JavaScript files as input. Then it uglifies the contents, concatenates them all into one file, and stores them in the desired location.

gulp.task('scripts', function() {
  var scriptSrc = [
    'js/vendor/jquery-1.10.2.js',
    'js/vendor/jquery-ui.custom.min.js',
    'js/vendor/moment.min.js',
    'js/vendor/handlebars.runtime-v1.3.0.js',
    'js/vendor/ember-1.3.2.js',
    'js/vendor/ember-data.js',
    'js/vendor/local-storage-adapter.js',
    'js/helpers.js',
    'js/main.js',
    'js/templates.js',
    'js/components.js',
    'js/models/*.js',
    'js/controllers/*.js',
    'js/router.js',
    'js/views/*.js',
    'js/fixtures.js',
    'js/routes/*.js'
  ];

  return gulp.src(scriptSrc)
    .pipe(uglify({ mangle: false }))
    .pipe(concat('main.min.js'))
    .pipe(gulp.dest('dist/js'));
});

File Watcher Task

This creates a watch task which has several subtasks inside of it. The subtasks watch several file types each. When any of the watched files change, the appropriate task gets triggered in response to that change.

gulp.task('watch', function() {
  //watches SCSS files for changes
  gulp.watch('scss/*.scss', ['css']);

  //watches handlebars files for changes
  gulp.watch('js/templates/**/*.hbs', ['templates']);
  
  //watches JavaScript files for changes
  gulp.watch('js/**/*.js', ['scripts']);
});

How to Use the Tasks

To show how to use the above tasks, I will show you the two ways in which I use them while developing an Ember.js application.

Development Usage

During development, I need to be able to compile SCSS, compile Handlebars, concatenate CSS, concatenate JavaScript, and uglify it. The files need to be watched for changes. Hence, I set up the following task to run on the command line.

gulp.task('default', ['css', 'templates', 'scripts', 'watch']);

Here, I am setting up a default task for Gulp.js. It gets run using the gulp command in the terminal. This will start a background task because of the watch task dependency. Anytime a file is changed, the tasks inside of the watch task (css, templates, and scripts) are run.

Production Usage

During production, when I am ready to ship the application, I need the dependent tasks of the default task except the watch task. This is because I will not be doing any changes to the files, and I need the build tools to run only once. This gets run using the command gulp production, which looks like this:

gulp.task('production', ['css', 'templates', 'scripts']);

Conclusion

That concludes our tutorial on how to use Gulp in your Ember.js project. We have defined several tasks to do a combination of common jobs. Be aware though, that you can mix and match jobs. For example, you can turn off uglifying of JavaScript code during development and only turn it on for you production task. A way to do this would be to define two separate tasks, one for development and one for production. Also, these tasks are only specific to my project. I urge you to look at the documentation pages for each of the plugins. These have more in depth information to further customize each of them to fit your needs. A good place to start would be the Gulp.js plugins page.

I hope this was useful, and as usual, please let us know if you have any questions or have something to contribute to the points above.