Lesson Weekend

We've been doing a great job of optimizing our app for the browser, but let's think about our development workflow now. Our gulpfile is growing. Each task that we add takes processing time. Are all of them necessary all the time? For example, if we were minifying a lot of files, this task might take a significant amount of time to run. This is worthwhile for optimizing a build that is going to be used by live users - we call this a production build. But we don't need to re-minify our JavaScript over and over again as we develop.

Build Tasks

Let's add our build task first! We'll put this at the end of our file, since it will use our other tasks.

gulpfile.js
...
gulp.task("build", function(){
  if (buildProduction) {
    gulp.start('minifyScripts');
  } else {
    gulp.start('jsBrowserify');
  }
});
...

Each of our tasks have their own dependency chains so all we have to do is specify the top level task that we want to run based on whether we are in development mode or deploying a production build.

Environmental Variables

We should have one set of tasks for a development build (the copy of our project we work on while we're still developing it), and another set of tasks for a production build (the copy of our project that will eventually be our 'final draft' that doesn't require tools we needed to develop it, like linters).

One good way to accomplish this is with an environment variable. This variable will simply indicate which environment (development or production) is being referenced.

Managing Environmental Variables with gulp-util

First, as usual, we need a new package from npm. It's called gulp-util. Let's install it as a development dependency:

$ npm install gulp-util --save-dev

Then let's require our new package at the top of our gulpfile:

gulpfile.js
var utilities = require('gulp-util');

Now, we're going to create an environment variable called production and we will use it inside of a new gulp task called build. The environment variable will tell our build task whether to create a development build or a production build. If we want to make a production version, which means we are including minification, we would first need to to tell gulp which kind of environment we are using.

gulpfile.js
...
var buildProduction = utilities.env.production;
...

Then, we can use this command:

$ gulp build --production

The presence of the --production flag sets our environment variable to true. If we want to make a development build, we would just leave it out and would run this:

$ gulp build

As an organizational suggestion, we will place this at the beginning of our gulpfile, after the require statements. Since we are setting up a variable in this block that we will use later, it makes sense to put it with the require statements because they are also declaring variables.

Clean Tasks

The next thing that we're going to need is a task to clean up our environment before we make a build. We want to make sure that we are using up-to-date versions of our files every time that we build. To this end, we need a way to delete files using gulp. Surprise! There's a package for that, called del, which stands for delete. Let's install it:

$ npm install del --save-dev

And require it at the top of our gulpfile:

gulpfile.js
var del = require('del');
...

Now here is what our clean task should look like:

gulpfile.js
...
gulp.task("clean", function(){
  return del(['build', 'tmp']);
});
...

We pass del an array of the paths to delete and it removes them. Here, we're telling it to delete the entire build and tmp folders. We'll put it right before the build task and call it automatically by making it a dependency of our build task. Whether we're making a production or a development build, we will clean up first.

gulpfile.js
...
gulp.task("build", ['clean'], function(){
  if (buildProduction) {
    gulp.start('minifyScripts');
  } else {
    gulp.start('jsBrowserify');
  }
});
...

Now, whether we run gulp build or gulp build --production, we will have a fresh folder of the newest files to work with. We can keep adding to this build task as we develop and expand our gulpfile - for example we could include tasks for compiling and minifying CSS.

gulp.start

Finally, a short note on gulp.start. The gulp.start function is undocumented on purpose because it will be deprecated in a future version of gulp. In fact, it is actually inherited from a different framework. However, it is very common to use it in this fashion to trigger tasks based on conditional statements. But developers are encouraged to use dependencies wherever possible (that array of other gulp tasks that run automatically) rather than gulp.start to trigger tasks at the correct time.

Let's try it out! If we run gulp build in the terminal, we can see that it runs clean, build, concatInterface, jsBrowserify, but not minifyScripts. But if we run gulp build --production, we can see that it runs minifyScripts, as well as all the previous tasks.

Terminology


  • Production: The environment that is live for end users.

  • Development: The environment where code is built.

  • Environment variable: A variable that indicates which environment - production or development, for instance - is being referenced.

  • gulp-util: A npm package that manages multiple utilities, including environmental variables.

Tips


  • The gulp.start function is undocumented because it will be deprecated in a future version of gulp. However, it is very common to use it to trigger tasks based on conditional statements. Developers are encouraged to use dependencies (that array of other gulp tasks that run automatically) rather than gulp.start to trigger tasks whenever possible.

Additional Resources