baumgartner_00

By Stefan Baumgartner

In this article, excerpted from Front-End Tooling with Gulp, Bower, and Yeoman, I talk about Gulp’s build tools.

Build tools, in general, consist of at least two parts: The tool executing the build, and a build file containing all the instructions for the build tool. Gulp makes no exception, but due to its Node.js roots, the tool itself is split up a little more. Figure 1 shows a quick overview of the compositing parts Gulp consists of.


baumgartner_01

Figure 1: The Gulp CLI starts the local Gulp installation with the parameters instructed on the command line. The local installation takes the local gulpfile, which in turn loads gulp plugins and defines tasks using the Gulp API. Gulp itself runs and loads said tasks.


The Gulp CLI. A command line interface meant to start off Gulp from your project’s root folder. This is also what we refer to as “global Gulp”, because it’s available everywhere we are in our file system. It needs…

The local Gulp installation. For each project you are going to install Gulp separately, making sure that the system you put together works with your project’s demands. Removing Gulp from your global environment and attaching it to the projects themselves helps greatly when you’re dealing with version updates. The local installation also exposes an API you can use in…

A Gulpfile. The Gulpfile contains all your building instructions. Build systems in general need those build files to know which tasks to run. Make uses “Makefiles” do bundle different command line calls in tasks. A Gulpfile does the same thing, but as opposed to other build systems, it’s written entirely in the same programming language it was meant to build: JavaScript. This means you can almost put anything in there which is interpretable by the Node.js environment. This also means that you have access to the existing world of node modules which you can incorporate into your build file, along with …

Gulp plugins. Most of the tasks we’re dealing with need some sort of file transformations, and with Gulp plugins provided by the original Gulp authors as well as the Gulp community, we are able to handle those transformations. At the time of this writing, Gulp’s plugin directory already counts over 1,400 available plugins.

Let’s look at those parts in detail.


Gulp Command Line Interface

Gulp is a Node.js module, and as with other Node.js modules, it can be used two ways: Installed globally, it works as a command line tool, installed locally, it’s a library. Gulp is no exception to this rule, but in Gulp’s particular case, the global installation is dependent on the local one. Figures 2 and 3 illustrate this difference.


baumgartner_02

Figure 2: This illustration shows the two ways a Node.js module can be installed. If you install a different tool globally, it just provides is functionality as an executable from the command line, working with the files you want to change. Installed locally, you can use the same functionality but in your own programs.


baumgartner_03

Figure 3: With Gulp however, the local installation is both tool and library. It works with the files in your project folder, the Gulpfile, and is used by such. The Gulp CLI just takes care of booting up the local installation.


Gulp’s command line interface just provides an entry point for the local installation, forwarding all the parameters entered and kicking off the version you’ve installed for your project. From there on, the local installation takes the lead and executes your build.

So the CLI is stripped out functionality from the original Node.js module. The decision to make the CLI rather dumb and having the whole basic functionality locally available allows for a more version independent execution: Imagine you have a project running the legacy version of Gulp 3.8. The CLI will be able to execute this project because the interface to the local Gulp installation is the same. A newer project running on Gulp 4 can be executed with the same CLI. In the end, you will most likely never update your command line interface, but be able to run all Gulp projects you will ever create.

With Node.js installed and your terminal (or Bash) booted up, install the command line interface with

$ npm install -g gulp-cli

Note the “-g” parameter after “install.” It tells your Node package manager to make this one globally available.

Note

On some systems it’s necessary to add the “sudo” prefix to install globally with admin rights.

Once NPM has finished, type in the following to your command line to make sure the installation has worked:

$ gulp --version

It should output something like this:

[12:04:15] CLI version 0.2.0

The first step is done: We have the Gulp CLI on our system.


The local Gulp installation

The local Gulp installation, as mentioned earlier, has two main purposes: Loading and executing the building instructions written in the Gulpfile, and exposing an API which can be used by the Gulpfile. Figure 4 illustrates this.


baumgartner_04

Figure 4: The local Gulp installation has an interplay with the Gulpfile. First, it loads the Gulpfile available in the project and executes the tasks defined there, as instructed by the command line interface. Second, it provides the Gulpfile with a basic API which is needed to create and define tasks.


For the purposes of this article, those three methods of Gukp’s API are necessary:

  • gulp.task – As the name would suggest it, it lets us define a task, which can later be executed.
  • gulp.src – The “src” method is made to load the source files (hence the name) which we want to process.
  • gulp.dest – After processing, the “dest” method will save the results in the directory passed as parameter.

To install the local Gulp, open your command line, move to the directory where you unzipped (or cloned) our sample project; not in the “app” folder directly, but one level upwards where the “README.md” file is located. In there, promote the whole folder to be a node module by typing

$ npm init

What follows is a short questionnaire asking you for information about your project. Since you possibly don’t want to publish your new module to the NPM registry (at least not now), you can leave everything to its default value. Once you’re done, you’ll see that a new file called “package.json” is available in your folder. This file will store all the information on which node modules are necessary for your application – the so called “dependencies” – and in which version they have to be. This file is like the core of every node project, and some plugins access it directly to get information on installed modules.

As mentioned above, the “package.json” file stores the node modules our project depends on, and can store both runtime dependencies (modules the project needs to work properly) and development dependencies (modules we need to develop our project). Since our build tool falls into the latter category, we install the local Gulp installation with the following command.

$ npm install --save-dev gulp

Gulp is being downloaded, and the “save-dev” parameter stores the correct version into our package.json file:

{
  "name": "sample-project-gulp",
  "version": "1.0.0",
  "description": "The sample project we will use throughout the Gulp chapters",
     ...
  "devDependencies": {
    "gulp": "^4.0.0"
  }
}

Doing a version check again (with gulp –version), we see that the output has changed. The Gulp CLI recognizes our local installation:


[20:40:12] CLI version 0.2.0
[20:40:12] Local version 4.0.0


The Gulpfile and Gulp plugins

The Gulpfile is a JavaScript file containing all our building instructions. Building instructions contain a series of commands which can be understood by the build tool itself. For Java’s Ant build system it’s an XML file where each XML tag represents a command available in the current eco system, GNU Make on the other hand has a simple definition of tasks and dependencies and executes software which is available on the shell. With Gulp however, we write JavaScript, and are thus able to use all the goods the Node.js environment has in store for us.

We use the API provided by our local Gulp installation, and we load a series of Gulp plugins to combine them in self-written tasks (see Figure 6).


baumgartner_05

Figure 5: The Gulpfile.js loads the local Gulp to get access to the API (.task, .src and .dest). It also loads Gulp plugins which in their turn provide another API for executing the task they were created for. In our Gulpfile, we combine those two things: With the Gulp API we define our tasks, which are then known to Gulp, and in those tasks we execute the plugins we loaded.


Gulp plugins are node modules written specifically for the use with Gulp. Once they are required (which means: loaded from your Gulpfile), they allow you to execute the job they were created for. For example: The plugin gulp-concat was made to concatenate a bunch of files into one. Those plugins have been designed to work on a very atomic level: Instead of trying to be the jack of all trades and thus getting monolithic, they do just one single and simple job, and are meant to do that one job well. For concatenation, the objectives for the job are very clear, and there’s no doubt in what’s the output of this job.

For Gulp, this means that we end up with a lot of plugins which we need if we want to do more to our files than what can be done with a single piece of software. We draw on a multitude of smaller, sharp pieces and compose them into something bigger.

Gulp plugins are installed at the same place where our local Gulp installation is. We even use the same command using NPM. For our samples, we will install all Gulp plugins which we need right away on our shell:

$ npm install --save-dev gulp-concat gulp-uglify gulp-less gulp-autoprefixer gulp-minify-css gulp-jshint

Also we create a file with the name “Gulpfile.js” in the same root directory. It should be on one level with the “node_modules” folder. Remember that the content of this file is just pure JavaScript written for the Node environment. So this is also the part where we are going to finally code!

With our plugins and the Gulpfile all set up, we are able to define our building instructions.