What do you want to learn?
Skip to main content
by John Papa
Start CourseBookmarkAdd to Channel
Table of contents
What to Expect
A Glimpse of What You Will Learn to Do
Environment and Prerequisites
The Value of a Task Runner
Using Gulp as a Task Runner
What's in It for You
Choosing Between Grunt and Gulp
Gulp Streams in Action
Streamline Your Tasks Using Gulp
4 Things You Need to Know About Gulp
Overview of Gulp APIs
Before we get everything installed, let's take some time to understand what we're getting with Gulp with four things we need to know. Gulp is going to pick up files in a stream and then it's going to process those files, or examine them, and then it's going to write out new files, quite possibly in an altered state to a destination. Basically in one end, and out the other. And the key to understanding Gulp are it's APIs. The good news is that there's just four. So we're going to explore all of those in this module, the gulp.task, gulp.src, gulp.dest and gulp.watch. For each API, we're going to cover what you can do with it, how to write code with it, of course, and when it adds value for you to use it.
The second API we're going to looks at is the gulp.src. It's the beginning of the stream. And gulp.src accepts two parameters, the first of which if required, and that's the glob, which is a file pattern match for the source files that you want to enter into the stream. In this case, we're passing in the source files under src, and all the sub-folders optionally, and then also any files that match *.js. So that'll take in that set of files and then also it'll emit any files that match to it. And optionally, we can specify other options to apply to the glob, too. Well, let's take a look at what those might be. So for that second parameter, we can actually set things like the options.base. So this is actually an object literal, which has other properties to it. So this means that, in the example here, we have the base property for the options is going to be set to the src/. That means we're explicitly saying that the base of this file pattern matching is source, so we're not going to include that when we actually get these files and what we emit. So for example here, when we send things out to the build folder, we're actually going to be sending out build/app/admin/admin.js. There would have to be a file called admin.js there. And therefore, the source is actually omitted from that. Now by default, if you don't pass in the base, you're going to get everything before the glob. So here in this example which is a little more common that you might see out there in the source without that actual options, now we're saying everything from source and then there's the glob starting. In that case, we'll get the same results since the base default's two source. So when's it a good idea to use gulp.src to stream files? Well whenever you want to stream those files they have to be linted or tested using things like jshint or jscs or maybe Karma to run your tests with Mocha or Jasmine. Anytime you want to optimize your files. So anything you want to have optimized for maybe CSS compilation from lesser Sass, or maybe you want to minify or concatenate your code. That's a great idea to stream the files in first, because you have to have the files before you can do anything to them. And then of course, anytime you want to modify files that you're going to be writing out. They have to be in the stream before you can actually do any of these things to them.
The third API we're going to look at is gulp.destination, which is where we're going to write our files out to. This one has a simple API where we pass in the folder of where we're going to send the files. We saw this in the previous examples, when we take in those files in the stream, we have to put them somewhere at the end. In this case, we're going to put a file called all.js in a folder called build. So piped files are written out to the file system. And optionally, we can specify other options too, like to the output folder itself. Like we can change the current working directory or the mode for permissions. So when do we want to use gulp.dest? Well, it's pretty obvious. When we want to write files out that we pulled into the stream. Or, maybe we want to write to a destination that's different from the source, maybe move it from one folder to a distribution folder or build folder, or we're going to write to the same file, or a new file after processing it.
The fourth API that we're going to look at is gulp.watch, which allows us to watch files and then perform a task or a function. So, one of the signatures allows us to pass in a glob to watch for the file. So, here we have task called lint-watcher, and it's going to be able to look at all the files that match this glob pattern, basically anything that ends in a *.js inside of the source folder, or underneath there anywhere. And then we can run a series of tasks, maybe one or more of those inside of an array and those task names in the array are exactly that. To the names of other gulp.tasks in the Gulp file that we want to run whenever that match is made. So, that's simply just an array of task names. It also has another signature that we can use. In gulp.watch you can pass, and for the final argument, a callback function, as well. So, maybe you don't want to call a task, but you want to call a specific function. So, whenever we match this particular glob pattern, we're going to call the function, and then it's also going to have an event parameter pass to it. That event parameter is going to tell us the type and the path of the event. For example, the type might be, it changed. A file was actually was removed, changed, or added, and then the path will be the path to that file. So watches are really powerful, and you can think of a lot of ways you might want to use those. So whenever you're making code changes, gulp.watch is really great, because you can use it to make your tests run whenever a file changes, you can automatically make your code lint, running jscs or jshint or whatever your favorite linting tools are. And, of course, you can just compile out to CSS.
Fitting Together the 4 Gulp APIs
So, in this module, we learned about the four main Gulp APIs that we're going to be using throughout this course. Well let's take a look at how they fit together. First we have the gulp.task itself, which defines the thing that we're going to be running. In this case, it has a name called js. And then, the function defines a definition of that task. Basically, what it's going to do. And then we begin the stream. And we pull those files into the stream using source, gulp.src. And we pass that, a glob pattern, to say, this is a set of files that I want you to pull into the stream. And then, we chain off of that source, piping in other different commands, things like jshint, concatenation and uglify. So, we can link to our code for code analysis, combine all the files into one called all.js. And then, we want to minify our code using uglify. We'll learn about these plugins and many, many more throughout the rest of this course, and how to use them. And then finally, we're going to use gulp.dest for destination, to send the resulting all.js file out to a folder called build. So here this task is using three of the APIs for us, task, source, and pipe. Well congratulations, now you're a Gulp expert, you've learned all four APIs. And just to recap what we've seen is gulp.tasks, which defines a task, there's src, which will read in the files into the stream, dest will write the files back out or whatever you process those files to become, and then gulp.watch will watch the files and then either run a function or a series of tasks. What's really cool about Gulp is it's just four simple APIs. That's it. And we can do a lot of really cool things, very powerful things, and automate a lot of redundant tasks using those. So in the next module, let's set up Gulp, and right our first hello world task.
Getting Started With Gulp
Getting the StarteSr Code
Let's go full steam ahead with Gulp. Wait a minute. We need to hold up first and make sure we have the right tools for this job. So in this module we'll do just that. We're going to get the code, get set up with node and MPM package manager, get Gulp and Bower, then set up a project and create a simple Gulp task. Then we'll be ready to rock and roll. Well let's kick things off by going out and getting the starter code for the application. So here's a GitHub weevil I created, with the starter samples that you can download. And there's a couple of ways you can get this. The preferred way is to use Git, or you can git clone the repo and just pull it down with this command. But you could also fork it, and then clone it, if you'd like to do that. Or you can just download it directly. Well let's go get the code together. So we'll start by browsing to this repo at github.com/johnpapa/Pluralsight-gulp. And then there's a couple of ways we can get the code. One way is to go over here and click on the download zip, over here on the right hand side, and that'll download all the code as a zip file. Another way is to use git, and we can click on copy to clipboard either using HTTPS or SSH. In this case, I'll use HTTPS. And then we can flip over to terminal, and now we can go ahead and create a folder where we're going to put this code and clone it using git, so I'm going to do that right in my home folder. And you can do this in any folder you like and make a directory and call this code. Then we're going to go inside the code folder and then type in get clone and then paste in the command that we just copied off the webpage. So when I do this it's going to clone all the code locally. So now if I take a look at where I am I can actually look inside there and see if there is a folder called Pluralsight-gulp. I can go into there and I can take a look. And if you're on Windows, you can type dir. Do the same thing. And I can see all the files are here. So now we have all the starter code we need to get moving.
Now that we've got the starter code, let's go ahead and make sure that we have node up and running on our machines. Now if you already have node, you can skip this section and go to the next video clip. But if you don't, you may want to follow along here. Now we have instructions for both OS X and Windows. So if you're using a Mac, you want to get Homebrew. That's one of the best ways to get and install things for a Mac. Now to do that you want to go to this brew.sh URL and download Brew, it's pretty easy to get. And basically it becomes a shopping cart where you can just shop for anything you want to put on a Mac. One of those things might be node. So you simply type the command line after you've installed brew, brew install node. And it puts it on there for you. So Homebrew provides a consistent way to go out and get node and install it on a Mac. Now if you're running Windows, there's something very similar. It's actually called Chocolatey. So Chocolatey. You go up there to chocolatey.org and you can download that. And there's instructions for doing that on the web page. And then you can run similar commands to install node on Windows. So you can run choco install nodejs. And then I find a, I usually like to run choco install nodejs.install right after that. So either way, this will get you up and running with node on your local machine. Now a couple tips here for OSX and Windows. If you're running on a Mac, one of the things you're probably going to run into sooner or later with node and MPM. Into a package manager, which we're going to learn about shortly. When you start installing packages that you want to use from the command line, things like Gulp, you're actually going to be prompted to have to use sudo, which is basically the root administrator for Mac and OSX. Now you can do that, but once you go down that road you're actually using sudo for all your globals, and you're going to need permissions to do that. But there's actually a way where you can alleviate yourself from having to use sudo at all. Now I've written up a blog post on how to do this, that borrows from a couple real powerhouses out there in the node MPM industry, and it shows how we can actually alleviate the need for using sudo. So if you haven't set up node before or even if you have, you might want to go check this out first. But what does this really do? The net effect is it allows you to type things like npm install-g and then the name of the package like Gulp, instead of sudo NPM install-g Gulp. And under the covers what really happening is, the reason we don't need sudo is because the packages will then be installed in a folder that doesn't require root permissions. Whether you choose to go sudo or no more sudo, I definitely recommend reading this post and learning more about the process. In this course I've actually alleviated the need for sudo, so you're going to see me typing in NPM install-g. And you're never going to see me type in sudo. If you're running Windows, don't worry. I've got some tips on how to run node on Windows as well, in case you run into any hurdles. And don't worry if you forget where some of these links are, you can always go back to the starter code page and on the main Read Me there, there are links to all these tips.
Installing Chocolatey and Homebrew
So let's take a stroll out to Chrome and we'll check out chocolatey.org. This is where we're going to go if you're on Windows, to basically install the installer for installing node on Windows. So, here on the web page, you can see the easy install. You just copy this script, and you past it in. And then you run it, and then you get, chocolately. So, great. One you've got chocolately, what do you do? This is when you can run commands like choco install git, or choco install node js. So go ahead and get that install it. And then you can make sure you can run the choco install no JS. And choco install no JS.install. Now I mentioned a couple tips on a post. And if you click that link it actually brings you over here to a post that I wrote about tips for running node in a NPM on Windows. And you'll notice here I mention getting visual studio. And I highly recommend the visual studio community edition which is free. Or also the latest version of Visual Studio, which is now 2015. And then once you get that, make sure you've also got git, and then chocolatey. And then here's the commands you can run. Choco install node.js, and node.js.install, and some tips for installing Python on Windows if you need that. But if you're running on OS X, we want to head over to Homebrew. And brew is at brew.sh, and that's the URL for it, you go get that it's the package manager for OSX. It's basically the chocolatey for windows, you have brew for OSX. So first if you don't have brew you want to scroll down till you see the install, and you want to run this command here to basically go out and curl and get Homebrew and put it on your machine,. And once that's there, you are all set to run brew commands. So what do you run? Well, we've got that tips page here for how do you install node and run NPM without sudo on OSX. And if you scroll down, you'll see a couple of instructions down here. First of all, there's the Homebrew command that you can use and we just saw that in the previous page. And then if you didn't already have node, you can install it here at brew install node. Then you can call all these instructions and it'll also help you set up running node without sudo. And when you're done, you should be able to run some verifications, things like running node-v and npm-v to make sure that you actually have node up and running the way it should be. So let's take a look at that. If we head over to terminal. You can see I've already got things installed here. And if I run node-v, that's going to run node and check the version. Currently I have 0.10.33. I think the latest right now is 0.10.35, so we can upgrade that. And then also npm-v will show me the latest version of NPM package manager, which we're going to use. Which right now is 2.1.16. And if you run these two commands when you done installing node that means you've got node in NPM and you are good to go. And if not please review the tips on these pages. Notice I pulled a fast one on you there.
Installing the Gulp CLI
Installing Gulp and Bower Globally
Creating a Local Package for a Project
So just like we have global packages, we're going to need some local packages for our application. Things that our application will depend upon. And to do that, we're going to need NPM, once again. So, here, we're going to install packages specifically for a project, locally. And to do that, we're going to use NPM install without the -g. Really important here. No dash g, at all. And then we're going to say --save-dev, and then the package name. So, let's examine this is a little bit here. NPM install is going to install a package. The package name is that package. And the --save-dev, that's going to say it's a dev dependency, so we'll learn about that in just a moment. First we run this command, NPM install gulp --save-dev and yeah, you may have run something similar to that just a moment ago. Now we're running Gulp locally for our package. We installed Gulp globally so that we can use that for the command line everywhere. But now our particular project, this Pluralsight-Gulp project is going to need Gulp locally. So we have to run this command. Save-dev is going to save it to the devDependencies package JSON file. So inside the package JSON is basically a manifest for all the dependencies that we're going to be having for our project. And it's got a section there called devDependencies. Now why is it dev? Because we're going to be using development code, hence development time for reusing Gulp at. There's also a --save, which is a runtime dependency that can be saved. So you can use your --saved-dev, or --save. So here, we're going to use save-dev, because we're going to install Gulp locally for the project. Super important. Be in the right project folder. Wherever you do this NPM install, with, --save-dev, or --save, it's going to install it in that particular folder. That's a local install. So make sure you get to the Pluralsight-gulp for what we're doing here. So what does package.json look like. Well once you've actually installed Gulp, inside the package.json, you'll have a section called devDependencies which has Gulp and then the latest version there. So Gulp is going to be your first item in devDependencies because we have nothing in there right now. And let's take a quick moment to go over the differences between package dependencies. There is dependencies and devDependencies. So dependencies are things that are going to be needed at run time and things like Express, or Angular, or Bootstrap. When we run our project, anything that's needed to actually run the app, that's a dependency. And the way to signify that it's a dependency is to use NPM install --save or bower install --save. For things that are coming for Angular, for example, and we go in the client means bower install. Things like express that we use on the server we use NPM install, but we're going to be doing a lot devDependencies in this course. So let's learn about tech because we're going to be needing this during development, and things like Concat, or Uglify or JSHint or Karma for testing. And run that is going to be NPM installed --save-dev. So pretty much everything we use here for all the Gulp dependencies is devDependencies. If we open up the project inside of one of our editors like brackets here that I'm using we can then look inside the package.JSON and in here make this a larger screen. We can see that there is a dependencies which is the stuff that we're going to need to run the project, but there's nothing in devDependencies down here in line 27. Let's go fix that. We want Gulp to be in here. So, over in terminal we can mpn install and remember now we're not going to run -g, but we are going to run --save dev because we want to be a dev dependency and we want to do Gulp. So, let's go ahead and install that. It'll go out and grab Gulp, and it'll put it locally in this package. Now if we look over on the left-hand side we can see that it actually put Gulp version 3.8.10 inside of our package JSON, and now we've got our first package locally in the project.
Creating a Gulpfile.js
Now that we have Gulp in our local package, let's go ahead and create a Gulp file. A Gulp file is basically the manifest of where all of our Gulp tasks are going to live. This is where we define our tasks that we're going to run. So before we can start using Gulp tasks, we have to learn a little bit of Node.js with the word require. And you can think of the word require as a way to import or to use or reference different modules in Node. Well, what are we talking about here? One of the modules we're going to reference is Gulp. We just got Gulp by using npm-install. Now we have to be able to reference it using require. So require is a keyword in node. So we're going to say var-gulp, declare the variable, and then we're going to require Gulp, the mod that we're going to use. So it's going to obtain the module and reference it. And then once we get that, we can create our first Gulp task. And we're simply going to say gulp.task, which we learned about in the API in the previous module. And then we're going to name it hello-world. And then we'll just put out a message to the console. So it will simply write out to the console and execute just by typing in Gulp hello-world. So let's go do this together. So let's head back over to our project, and let's create a new file. And up top here, let's go ahead and put in, var gulp = require('gulp'); and then we're going to save that, and we're going to name that gulpfile.js. Now we have that, we get our syntax highlighting in here. And then once we have Gulp we can create our first task. So the task is going to be Gulp.task using our API. We have to give it a name, so we'll call this "Hello World" and you can use dashes. And then the task is simply going to call this function. So there's our function. And what do we want to do? In this case let's just do a console.log. We'll just make sure our task works. And we'll say our first hello world task. And yes, we'd like to spell correctly. So let's flip over to Terminal and we'll make sure we're in the right folder. And we are. So now, we can run our task. We say Gulp and then hello-world. Make sure it matches what you typed in exactly for the task name. And there we go. We're saying we're using the Gulp file. It automatically looks for a file that's named Gulpfile.js. And then we're going to start up the hello world task. And then it's saying, hey, here's our first hello world Gulp task. And then it finishes it. And that's it.
Oh yeah, baby, we are ready for Gulp now, we're all set to go. In this module we took care of all of our business we needed to do to get going. So we used Git to go get our starter code, or you could download that for the zip file, your choice. And then based upon whether you're in Windows or OSX. You then use Brew or Chocolatey to go install node. Once we did that, we have node and NPM. We used NPM to install our global package. In this case it was Gulp and Bower. And then we had our project file, where we installed using npm install-save-dev to go get our local package. In this case, just Gulp. And we created our first gulp.task, Hello World. And wasn't it amazing? So, in the next module, we're going to be continuing to build up this Gulp file, so you can put a lot of useful stuff in there, unlike Hello World, that'll let us do things like analyzing our code and testing it.
Code Analysis With JSHint and JSCS
Code Analysis With JSHint and JSCS
JSHint and JSCS in Brackets
Let's take a look inside the project at some of the existing code. This is the customer detail controller, which you can find inside of the source folder. Then inside of Client, App, and then inside of Customers. And, let's look at what happens when we use an editor that respects the jshintrc or jscs files. So first, let me just put a couple line breaks in there, and I'll press Save. And as soon as I do, you can see I've got a jscs problem, a code style problem, where I've defined a find a rule where I don't have multiple line breaks. Well, let's say I'm just typing along and I type in a function and I'll call this function foo. And then let's create some lines of code in here. And let me say, I get some bad intending, and then I'll do var x equals 1. And let's say I forget a semicolon there and I'll add an extra one here. Now when I press Save, you're going to see jshint is telling me all the issues that I have for the code style. And we'll click and go right to the line. And also jscs will tell me what I've got going on as well. And then I can fix those. And when I do, I get less issues coming up. So once I tidy it all up, I start having less problems. And then, I'm good to go. Right? Absolutely. So why is all this happening? Let's take a look. Inside of the editor is respecting two files we have. One is this jscsrc, right here, where you can see the different rules are defined in a JSON file, and then the other is the jshintrc file, right in the root. Now I'm using Brackets here, but this works in Sublime, Visual Studio, and WebStorm, all the major editors that are out there. And the great thing about this is it works in the editor. But what if we want to see eye processor wrong, we want to check everything. And plus, this is only working in the editor in the active file that's open, whether I've got hundreds or thousands of files. Well, I want to make sure I can check them all in one shot. And that's where Gulp comes in. So let's take a look at how we can use Gulp to solve this problem at a large scale. So
Installing JSHint and JSCS for Gulp
we're going to use JSHint and JSCS inside of Gulp, and to do that we need to install it. So, how do we do that? Well, we go to Terminal and we can install using npm install gulp-jshint and gulp-jscs, and then we're going to use save-dev to make sure that we get it local for the project and get saved to the package JSON file. And we do this one time, it just puts it in the manifest for the project, package JSON. And then we'll use a little more node with require. We're going to go into our Gulp file, and we're going to add a new require statement, and then pipe the stream through both jscs and jshint.
Coding the JSHint and JSCS Task
So let's flip over to Terminal and we'll make sure we're in the right folder for our project, and we are. It's basically where we left off in the last module and now let's install the packages. We use npm install. We want to save these Gulp packages to the package JSON, so we'll say --save-dev, because they're development time dependencies, because we're using them for Gulp. And the two we want to get are jscs and then gulp-jshint. So we'll run that. It'll run out to the internet and go grab those. While it's happening, let's look at the package JSON file at the bottom. Notice we've got the dev dependencies only has Gulp in it right now. But as soon as it goes out and gets these packages, you'll see them, voila, appear over in the right hand side. So now that we have them, let's go inside the Gulp file and we'll code up our tasks. So let's flip over there and we'll go to full screen with this. Notice first of all that I've got a JSCS problem in my project. Right there, I missed a space, so let's go ahead and save that guy. And now we can delete this task for hello world. Instead let's use this one and let's call it vet for vetting out our code. And we're not going to console log it. So we'll delete that. Now, we're going to need some more var statements up here. The first one we're going to do is to get jshint. So we'll do that. And we'll do the same thing for jscs. Once we get these, we can now use those inside of our Gulp task. So the first thing we want to do is actually use the source. You remember, the source is going to pipe in all the files that we're going to be using. So for the source, why don't we set this up instead of going out and saying, hey, let's get everything that's got some kind of like a .js on it. Instead we can pass it in array. So let's do that here. Now first I'm telling it there's an array where first I want to get all the files that start with source, that's my root folder, and then any sub-folder that's got a file in it with js, and then also in my root, the files that are flat in my root .js. So the first one is going to get all my source code inside my source folder. And the second one is going to get anything right at the root. So that's going to catch my Gulp file and my karma file and any other JS file right at the root because I want to check those. So now that we've got our source, let's go ahead and pipe the files into one of our plugins. Well, we'll go ahead and choose jscs first, and then we'll pipe it into the other. And there we go. So now we have our stream setup, and we're always going to return the stream. We'll learn more about why we want to do that a little later, but trust me for now that we want to do that so it helps us build these tasks. Then we can format our code a little bit. So we're telling Gulp to read in these files and then pipe them to jscs and then pipe them to jshint and let us know what's going on. One of the things we want to do, though, with jshint is, it needs a special reporter. So jshint has reporter task that we can use to tell it how to behave. And then what are we going to use then? All right, after you're done with jshint, let's go ahead and use its reporter. And the type of reporter we're going to use is jshint-stylish. Now, one of the flags I like to pass to this, and you can check out these options on the jshint site, is verbose: true. That's going to tell us when we have an issue with jshint. Don't just use the standard error message, but also tell us what actually happened, so it was a code, like a w code, and it'll show those for us. For example, down below we can see W033 has a missing semicolon. So if we fix that over here, we're actually missing a parenthesis and that's what's causing most of our problems, we're good to go. But how do we get that? Well, we have to go get jshint-stylish, so let's copy that. And we'll come back over to Terminal and we'll go ahead and type in npm install save-dev, and then the name of that plugin. And that'll pull the reporter down for us so we can use it. And once we get that, we can go back and make sure we've got issues in a file and I've got a couple over here in this controller detail. You can put in any file you'd like, just make sure you clean them up later. And now I've got just JSHint issues. And let's go ahead and put a little bit of snuggling inside of my x equals. JSCS doesn't like that. And we'll run the command gulp.vet, because that's the name of our Gulp task. And we run that, we should see the problem showing up here. Now first of all, we can see the missing semicolon and y is not defined. Now if we come back over to the task over here, we can see that in the file first we've got the issues for jshint showing up. And then down below, we got the operator should not be sticking to the preceding expression. That's the jscs one. Now notice the W commands here. There are the codes actually from jshint, so W33 and then W117. So why would you care about those? Well one of the options you can do with jshint is you can say, all right, come up into my file. And I can say jshint, and then I can tell it to ignore a code. So if I want it to ignore a code, which I don't recommend in this case, but just to show you what those are good for, you notice now 33 disappeared from the line below. So I can get that out of here. Put it back in, and then I can fix my code. So once I fix my code, let's see what happens. We get rid of the snuggling, everybody's good there. Y is not defined. We'll make it defined. And now, if I rerun it, we should have no issues from either one of these.
Failing the Task
Now if you run this task in the CI process, you want that CI process to fail and actually stop if this doesn't pass all adjacent JSCS issues. You want to use an extra feature in here, which is another setting inside of JSHint which is going to be called fail. So I'll pipe this through the failure reporter for JSHint. This time, it's not going to send it to the screen. We're just going to tell it, hey, look, dude, fail if this thing isn't working. And that's all we need to do.
Conditionally Displaying the Source Files
Now sometimes I find it really helpful to make sure that this task is actually hitting the files that I think it's hitting. So I can read it here in the glob, but maybe that didn't catch the things that I thought it was going to catch. So we have another option we can do, and that is we can use a tool called print. Which is going to print out all the files that we're touching in this Gulp process. So let's pipe that in first. Right up top here we're going to say, all right, pipe in another plugin here, and that one's going to be called print. Well something we're kind of getting the hang of here is we're having a lot of plugins, and a lot of things are going to be showing up up top here. So let's put it in up here first, and then I'll show you a way we can solve that, too, but one thing at a time. First, we go ahead and get this guy. And we're going to pull in gulp-print. Now we run into this issue here where we really shouldn't use the word print, but we'll just call this gulpprint for now, and we're good to go. Now let's go back over to our terminal, and we need to install that. So we'll do npm install save-dev gulp-print. And that'll get added to our package JSON, and then we can use it. And he was pretty easy to do. So, before we print out everything in there, maybe we want to have a flag for that. So, let's come back over to Terminal because you're going to see all the stuff that's going to happen. And here's all the files it's catching. And that's good. We wanted to make sure we got all those files, so we're golden. But we want to write some code, too, to make sure that we can turn this on or off, because I don't always want to see that. So there is another utility called a Gulp if. Now Gulp if is going to say, if a certain condition, we'll put that here for a moment and that's true, then I want to run gulpprint. So where is this Gulp if coming from? Well, that's another utility we're going to pull in. So we will do that up here, and we will have another require statement and pull in what we want to pull in. So there's our gulp-if statement. That's going to be this variable and that condition is going to be from a command line. So we are going to use args, and we will make that be args verbose. Now to get that, we're going to use another require statement. And my favorite tool to go out and get the arguments is actually called yargs, which you got to say with a pirate accent like that. You got to go yargs! Come on everybody together now, yargs! So, we do that. We get yargs, and we use argv on that. And we have to go get those guys. So I'll type in npm install save-dev gulp-if to the get the first guy, and then yargs for the second. So we come out here and then it should go get those inside the packages. Now, if we look at our code, we can see we've got the args here, and if it seems verbose, it's going to use gulpprint. If it doesn't, it won't. So let's try this out. So we'll, now we'll type in Gulp vet without verbose, and we should see that there are no issues, and it's all done. Now let's try with verbose. Now we should see all the files that are actually getting hit. So this is a nice little handy utility that we can use to toggle different things. Gulp-if is conditionally setting things in the stream and then the args is going to help us pass in command line arguments.
Lazy Loading Gulp Plugins
So, we've got our file working with our task. The next step is do a little bit of cleanup. One thing you kind of are noticing here is that we've got all these guys that are kind of piling up, up here. Now, these two are not actually Gulp plugins. One's Gulp, and one's yargs. But the other ones are all plugins. Wouldn't it be nice if there was a way to say, just go get me all the Gulp plugins. Well, there is. So what I like to do is use a plugin for Gulp. Yeah, I know. And that plugin actually goes and gets all the plugins for me. And I usually call this one dollar sign, and then I just require in that plugin. And it's called gulp-load-plugins. So you get that guy there, and it's got an optional setting for lazy, which I like to set so it only gets the plugins as they're being used. Now once I get him, I shouldn't need these guys anymore. So, let's comment them out for a moment, and it tells me you've got lots of problems. Well, we know that. But down here, we can say let's get the dollar if, and then we can say, all right, well that's good, let's go get dollar if print. Now the convention is, it'll actually take the name of the plugin without the gulp dash in front of it, and it'll make a variable for it. So you can do that for this guy, and him, and him, and let's make sure we caught them all. So we've got our jscs, our print, our jshint, and we also got let's see, we forgot the if. No we didn't. He's right here. But we're seeing problems down here in JSHint. Why is that? Because we're also using this for util. So that's also a gulp-util, so we can do that down here, as well. So, once we do that we have no more issues inside of here, and notice we've now replaced all five of these lines with this one dollar sign. So, let's delete those. And now the only thing left to do is to go out and get that plugin. So let's come back into Terminal. And we'll do npm install, save-dev, and we'll get the gulp-load-plugins. And there we go. So now, if we run our task again, we can run Gulp vet, we should still be good to go. And we are.
Reusable Configuration Module
Compiling to CSS and Error Handling
There's widespread use of pre compilers in web development. Things like lesson SaaS. So they compile right to CSS for us. The good news is we can use Gulp to create a pipeline to do this for us too. So this module's going to cover our CSS preparation before we deploy the application. So in this module we'll learn how to compile the CSS, add vendor prefixes to it for things like MS dash or for WebKit. How to use swatches to automatically compile the CSS as we change our files. And then deal with handling errors gracefully. And what are these callback things inside of the Gulp tasks? And by the end of this module, we'll have coded a great pipeline for compiling our CSS.
CSS Pre-Compilers and Vendor Prefixes
We have a lot of options for compiling CSS. There's Stylus, there's Sass, and there's Less, too. Less is the one I'm going to choose in this course, but you could use any of them. And if you want to learn more about Less or Sass, you can check out Shawn Wildermuth's course here on Pluralsight. But let's take Less as an example. We might want to compile our Less to CSS using Gulp. Why? Because we want to compile before we actually browse the site. The Less is great, but the browsers understand CSS. And there's a lot of tools that will do this for us, and some of the features that Less has is variables that we can reuse, maybe the color blue all throughout your application. Different mixins and functions and operators. So for example we can use this Less up top to create reusable code that ends up creating this CSS in the bottom. Notice we use the base variable top in the Less for our shade of color and then we perform functions on that like saturate. And then the bottom, what actually comes out of that is not that exact base color variable but the actual hex value for the color after the operation. So you think of Less as a nice easy function as you perform on your CSS to basically make the CSS for you. And we'll be using Gulp to automatically do this conversion. Now another thing we like to do with our CSS is automatically add in vendor prefixes. And we're going to use AutoPrefixer to do that. Which will allow us post CSS to handle all the vendor prefixes. So we don't have to write them at all. It's going to be automated of course because we're using Gulp. And it keeps itself up to date by using the Can I Use site. So how does AutoPrefixer work? Well let's take a look here at some sample code that we have in CSS, so after we perform the less than CSS, we can take a look at this. In order, Prefixer will allow us to do things like browser options on it and visually cascade the results, so what does that mean? Well browser options, we can tell certain browsers, like maybe the last two versions, or cover a certain percentage of the market. For example, maybe we don't want any browser that doesn't have least 3% of the market. So, AutoPrefixer would take the sample code top and perhaps turn into what we see at the bottom down here. And we can see the visual cascade because we're lining up the transform origin. And who wants to write this code right? And keep up with all the changes in the browsers out there. So the great thing about these tools is we can write Less once, it'll automatically compile using Gulp over to CSS, and then we're going to add the prefixes automatically. Let's go do that.
Creating a Less and AutoPrefixer Gulp Task
Deleting Files in a Dependency Task
Now let's make sure we remove that style test. And now we'll close out these files, and we'll go back and we'll do a little bit of cleanup in here. And by cleanup I mean that every time we create the styles, we're overwriting this file here in the temp folder. We really should clean up that file once in a while, so we want to create a task that's going to clean it for us, and we'll call this clean styles. Now this task will go inside that folder and clean things out. And the way it's going to do that is through a function. Now we're going to be cleaning out other files too, so we're just thinking ahead a little bit here. So we'll create a variable for the files in case we add more than one later. And for right now that's going to be the config temp. And we'll want to take everything out of that folder that happens to be CSS. Once we have that file glob, now we can pass it to a function that will delete everything. Now there's a nice package in node called del, which will delete what we need. And to that, we want to pass in the file path. In this case, it's going to be the files. And that will delete the code for us. Now del is not defined yet because we don't have it. This isn't a Gulp package. And while there are some Gulp packages to delete files, quite frankly, we don't need a stream to do this. So let's not use one. Let's go ahead and just pull in the delete functionality. And again, this'll be for just development purposes. So that pulls in that package. And then we can go to the top of our code and require it. We go back up to the top. And I'll just keep them alphabetical for now, or at least somewhat alphabetical. Like that. And now that we have those, we can come back down to our clean styles. We can see that we're going to clean out what's there. So first, let's try this out. Let's come back over to our code and let's run Gulp, clean styles. And notice on the left, before we run this, we've got a temp folder with styles.css and when we run this, it should disappear. Come over here and it's been cleaned. Well that's great, but we want to run this before we run the styles task. So let's come up here and make it a dependency and we learned about this earlier in the course, we consider it a dependency task. So what this means now is that the clean-styles task, down here in line 29, is going to run before the task styles on line 19. Because of this array parameter that we popped in here. So that'll handle that for us, but what if we want to delete files later in other folders too. So, we might want to create a function for that delete functionality. Let's do that. So now let's create a function called clean. And we want to pass to it some kind of a path. And what's that going to do? Well right now it's just going to take in whatever you pass in, then delete it. And maybe we should use a log, right? So in this case we can use that log function. Can say we are cleaning house. That will take advantage of the utility that we have for Gulp to do our colors blue and will pass in the path that we are cleaning. So now that we've got that set up, we can now run this guide directly from there. So this task now just says okay, instead of calling delete directly, we can just call in clean and pass in the files. So I don't need that. So right now, it doesn't show a lot of opportunity, but when we have a lot of things we want to clean out, we've got one place to do that and it'll log it consistently. Now we still have a slight problem, but let's run this and just make sure it works. First, let's go back over here, and let's run styles. Now it should create the file. And then put it in that folder, and then if we just ran clean, which we could, we can go back and run clean styles, that should just clean it out for us which it does, but if we run something, let's say we stick a file in here that's not really our CSS file, let's create a new file, and we'll call this foo.css. So there is our foo file, now let's come back over here and let's run styles. It should kick off clean first and then wipe out the Foo CSS and the put the new one in there and it did. Now I mentioned there might be a problem and that problem is that the styles task is supposed to wait for clean styles to finish. Unfortunately, there's no stream in here so it's not really getting the screen back. So the cleanest way to do this is you want to make sure the clean styles task, because it doesn't have a stream. It uses a callback. So, you see this syntax used quite a bit, which it passed something into the function of the task that becomes the callback function. I like to call mine done. And then when I'm done with this what I want to do is have the clean function actually call it. So I'm going to add a new parameter to my clean function, which'll be my call back down here and after I'm done deleting, I want to make sure that I called done. Now luckily the delete function down here actually has a call back as its second parameter. So it will call down when it's done. So now if you run this again. Now if we flip back over, we can come back and run the styles again. It'll clean things and wait the proper time. And do it in the right order. Now we didn't happen to notice much here because it was really super-fast, but that kind of a thing is really important where you make sure you do the callback when you're not actually returning the stream. And for example, we're using the return of the stream right here on line 22. So that's why we didn't deal with it earlier. The last thing we need to check out is over in our index.html, where we're referring to the style sheet. Notice here on line 19 we've already got the linked style sheet set up. Right here where we're blinking. So we've got this temp set up to point to our temp folder. And then get our style CSS. It'd be great if we had a way to automatically save
Creating a Watch Task to Compile CSS
our CSS so every time we change a file, it automatically happens. So let's do that down here at the bottom, let's create a new task to kick off some watches, and we'll call this less watch. Now this guy's sole purpose is going to be to kick off that particular task. So first we have to use the API we haven't used yet in Gulp, which is the watch API, we learned about this earlier and it's going to watch a list of files, in this case config.less, see, we're already using that configuration. And then what do you want it to do? Well I want it to kick off all the tasks in this array. In this case, it's just one. And that's it. So if you pull them over, notice you have nothing in that temp folder. Now if we run our less watcher, it should open up. And notice it's not stopping, it's just watching. We didn't get the cursor back. To kill that I can Ctrl+C, or now let's run it again. Now let's go back over into our files. And we'll go look at our CSS in the less file. There's our less. Let's just add another variable in here. We'll add a variable in here for color. Nothing. And we'll go ahead and just stick another color value. And notice as soon as I saved, it actually picked that up, it cleans out the temp folder for me, and then it wrote out the file and compiled it to less. Now, one of the things that's kind of neat is we can see the path right there. Now, that's just a log message. We want to make sure that that didn't get picked up wrong. So go back over to the Gulp file. And we'll make sure inside of our cleaning. Did we **** anything up? Well we've got a path. It's just logging out whatever we told it to delete. So if we come back into here it's looking for anything that begins with temp star. That's not exactly what we wanted. We wanted temp slash star. So let's back track that a little. This here temp from line 41 is coming from the function on 40. Which then comes from the line on 31. Note, on this temp up here, it didn't start with anything. That tells me that this temp property right here might not be set properly. So I come back into the Gulp config file and I like to end my directories with a slash just to make it consistent, so we always have that same thing. Now, if we run this again, we'll kill it over here. We'll rerun our less-watcher. And then we'll come back into our styles, and then we'll just put a space in here, that's fine too. Notice it picked it up, and it's cleaning out the path the way it's supposed to be.
Handling Errors and Using Gulp Plumber
Sometimes when we have CSS, we have compilation errors. So let's take a look at what happens with our code if we forget a semi colon. And let's go back over and run our less watcher. And here he is. Now let's stick in the semi colon real quick. Make sure he works. Notice he started, compiled and finished. Now let's put the semi colon and remove it. And notice it started, compiled and it never finished. The thing you may not have noticed is over here on the left the styles didn't get regenerated. Let's delete this manually just to prove this. We will delete the style sheet look back in the less now let's go ahead and we will stick in something else in here like some gobbldygook. And press save it's no longer running. To prove it again here we going to run this right, we are going to run the watch. Now let's go over here and let's delete that. We still have an error because we don't have a semicolon at the end of line eight. It started, compiled, nothing finished. And over here we have nothing in the temp folder. So we have a problem but we don't know what the problem is. Basically it's cancelling everything in the stream, but not telling us. So what do we do? Well first, let's go back into our Gulp file and add some error handling. And to do that, inside of the pipeline right after the less statement, we can add an on. So that on is going to match a particular event. In this case, that's going to be an error. So we're going to do an on error. Let's call the error logger. So we'll defer it to an error logger function which we then need to define, of course. So let's come down here. And it's going to automatically pass in the error parameter which will come from the screen. And once we're inside of there, we want to print off what kind of error happened. So to do that, we'll just put a little bit of logging in here. So we'll say here's the start of the error, the error message, and then the end of the error, just so we can see it. And then whenever we do this, we're going to make sure that we emit, using this for Gulp's emit and we're going to end this and that way, the error logger up here on line 25 will actually end the pipe and give us some information, so that's the intent at least. Now it's come back over here, let's run our watch. And now let's come back into the less. Now we still have an error up here. We'll remove another semi-colon just to make it kick off. And this time, it did fail again. But now it's telling us all the information. Now that's quite a bit of information in there. It's hard to really track down what the issue is. It actually shows us more than we need. So let's try something else. Instead of using the on-error, we'll come back and run the Gulp file. Let's comment that out and use a tool called Gulp plumber, so I'll pipe in the Gulp plumber, we'll have to go get him, and he's basically going to handle our errors gracefully for us. It's basically going to replace the pipe method, and we're going to move a standard on air handler, for the on air event, it's going to unpipe the stream on air by default, so. That's a lot of gobbledy **** to tell us what's going on. Let's actually see it in action, right. So over here we're going to make sure we do npm install and then we'll say save dev and we'll use gulp-plumber. And while it gets that it's going to stick into our package.json. Now we have gulp-plumber. At this point, just to make sure we're not using our error logger function. And to prove it, let's go ahead and delete that down here. And we can delete the on-error line up here. So now, we've got our code. We've got less plumber. And we're going to auto-prefix it. And we're going to spit it out to the destination. Now let's run our watch, we'll come back to our less file, and we'll remove yet another. Well actually let's make it good first. We'll put the semicolons in place. It compiled it. Finished it. And you saw it show it up over here on this side. Let's manually delete that. It'll be a little tricky. Okay, he's deleted, now let's remove the semicolon, and this time, I started compiling it, and Plumber found an error. Tells us we have unrecognized input on line ten of a less file, which is right here. And it's saying that because it thinks that's the continuation of this color which is not really the good case. So we're going to want to put that guy back. And notice our stream is still working now and we got the compilation at the end. Now we can get rid of our color, nothing, because we're not using it and our auto watch is still working. So Plumber is a great way to keep the piping working still but show us the error messages and that's what I used.
So in this module, we learned quite about how we can compile into CSS using Gulp. And even do a little bit of error handling. So first, we pulled in the source files. And we used config, but here's an explicit less file we used. And then we took that and we're going to start compiling it. The next step was to handle our errors with plumber. And then we make sure we do the less compilation. And then we use autoprefixer to make sure we get the event prefixes in place. And then finally, we write out the less file to a CSS file. So in one end of the stream, out the other. So a recap, it's not just about compiling less or Sass or style-less over too CSS, but we're also doing things like vendor prefixes and handling events, like errors. We learn how to use that. But we also learned how to use gulp-plumber, which is a little more graceful way in this particular case. And we made a little more reusable code not only using configuration, but dealing with callbacks to help end the stream. And we did that particularly in the clean function. So you make sure after we clean out a folder, we let it know when it's done so the task can continue. That's especially helpful when we're about to start a task, and we want to make sure we clean out the destination folder first.
Gulp and HTML Injection
Exploring wiredep and gulp-inject
Removing Scripts and Styles From the Main HTML
Adding Bower Files Automatically on Install
Injecting Custom CSS
Serving Your Dev Build
Serving Your Development Build
When I'm writing code, I like to make sure that I can write the code and focus on what I'm doing, and then serve it up in node and then look at it in the browser really quickly. And then I can make changes and do it again. And we've been able to reduce down to two steps the parts where we get all of our HTML and prepare it, and then also run the node server. We'd like to do it to reduce that to one step, make it really easy. And add in the additional feature of restarting the node server when any node code changes. And of course, the overall driving factor has to be fast. Because when I'm in a coding mindset I want to stay focused on the code. I don't want any delays of ten or 20 seconds while I'm trying to make changes. So that's what we're going to do in this module.
Using nodemon in a Gulp Task
The steps we've taken so far have been pretty effective. We've gone through and created Gulp inject, which has made it easy for us to get everything ready to reload our HTML page. Now when we run the code, we run Gulp inject, and then node src/server/app.js. But this doesn't handle an extra case where a node code changes and we want to restart the server. So what you really want to do is prepare all the styles in HTML, and then run the node server, and then restart on any node server changes. How are we going to do this? We're going to use a Gulp task. We'll name it Gulp serve-dev and it's going to prepare the code for us. It'll run the node server, and then of course, restart on any node changes. Now, there's a great MPM module called nodemon which will actually restart the node server for us and watch file changes and handle events. Well, we're going to take advantage of gulp-nodemon. And the reason for this is that not only does all the things that nodemon does but it also adds support for running a task when any of the events changes. So why might we want this? Well, let's say we're starting a node server up, and on change and restart of that, we also want to run a task we've already defined, like the vet task we have, for doing our JSHint and jscs. So it's a little bit of extra functionality that we can take advantage of. So now that we know what we want, let's go make these changes.
Prepare, Serve, and Restart the Code
We've configured our Gulp file to have an inject task which handles getting everything ready and then we can serve the code. Let's run that and make sure we have things working. So first we run Gulp inject. And then after we do that we can then run our node task which is going to be node server and then app.js. And everything is running here and we go check it out in the browser. We can refresh, and it runs great. Wonderful! But let's go ahead and reduce that down now. So in a good working starting state, now we are going to write a new task down here, and we will call it serve-dev. So create the task. We'll name it. And we'll add in a function. Now we want this guy to depend upon a first-run inject. So let's go ahead and specify that. And now we need to serve the code using nodemon. So to get nodemon first, let's go back over to terminal. Do npm install, save-dev, and then we'll do gulp-modmon. Now that will install it into our project and then we can take advantage of that inside the task to kick-up our server. So now that we have that, let's go ahead and start writing our task out. So first we'll kick off nodemon. And now we have to tell it a bunch of options that are going to be in there. So let's go ahead and set those up. There'll be an options argument. And I always like to return from every one of my tasks as well. So those options here, we're going to say the node options are an object literal. Now we have to tell node what to do with all this information. Now where's our server located? What port do you want to run on? Things like that. So first there's a property that node mon likes called script. So we're going to have a script here and we'll use our config to tell it where that is. Now that's going to be a to do, and what's that guy going to be, well he's going to be our app.js file, the path to that. Now I also want to stick in a delay time, I like to give it a one second delay. We could make that configurable, but it's generally what I stick with in all of my projects, so we're going to leave it alone and then for the environment, we're going to pass in an environment variable. First our app server wants us to specify the port, so we're going to pass that in through a variable. And then second we're going to pass in the environment. Is it development time or build time? So we'll create a flag here called isDev and if it's dev we'll pass in the word dev. Otherwise we're going to pass in build. So where's that stuff coming from? Well for now we're just going to hard code isDev because that's all we have. Later on we will be toggling that as you might imagine. And if we flip over to our app.js file. And that's under source, and then server and then app.js. We'll see in here, we have got the port which we can override if somebody passes that in, and then we've got the node environment here on line 15. So that's what we are setting up in here the port and then the environment. And we especially want to spell that correctly. Now that's great. We've told it what to run, how long to wait before it reruns it, and then any configuration options it needs inside the app.js. But the final piece is how do we restart that? So we're going to set up a watch, and we're going to pass it a series of files. In this case we're going to pass it in through here. So we have to make a TODO here to define the files. Now once we have all of that, we can return nodemon and pass in the options. So let's go over to our Gulp config and we're going to create node server and server, and we also have to deal with this port variable. Now the port, I like to put up at the top up here. So you can see I typed this ahead for you. It's basically saying the port is going to be wherever port puts in the command line for the environment or it's going to be a config default port. So let's go into our Gulp config and we'll add that in here. So let's scroll down to the bottom, underneath our bower packages, we'll create a new section in here, for our node settings, and the first one we'll stick in will be defaultPort. And we'll default that to 7203. We can always override later. And then, we'll also put in our nodeServer. And this is going to be the thing we're actually going to be kicking off. So this one will be dot source and then it'll be server and then app.js. So we don't have to retype that all over the place. So did that cover us? We have defaultPort and nodeServer. Let's go back and check. Go back down to our task. Here we've got the port. We've got the nodeServer, we'll get rid of that TODO. We also have TODO for the server itself. Now that's going to be for the files its watching and then we'll restart with. So we'll come back in here and define what those are going to look like. So we've been listing files up here in this list. We have our file paths. Let's create one for server. And now, what's that guy actually going to equal? Well, we might want to reuse this guy, just like we did for clients. So let's go put him at the top. We'll say var server, and then we'll equal up here what the path will be for the server. So in this case, it'll be anything under source and then server itself. And that's going to be the folder. Now, come back down here for the server, itself. And we'll say, all right. You use the local variable called, server. And I'm also going to move temp from up here, because he's also a file path, and we'll stick him underneath server. Just to keep things a little bit organized. So now we've covered all three TODOs. And we should be able to go over and run our code. So, let's go back to terminal. And now let's run Gulp. And then we called it serve-dev. It should perform the injection and then crank up the server. And we can see here, it did. It started out wiredep, and styles, and inject, and then it started up our node server. So let's see this in action. First of all, let's do a Cmd+K over in terminal that'll clear things out. Just to make it easier. Let me crank open the app.js file. I'll make a few spaces. I'll just put a comment in there. I'm going to press Save. So when I do that, you're going to see after a very slight delay, it's going to crank up the node server, and it's listening on that port. So any changes that we make to this file will automatically get handled. For example, let's just change the port here to 8001. We'll override it and therefore you can see the change right here. So now we have a single command which will crank up all of our code in our server and then restart whenever we change any of our server code.
Run Tasks on Node Restart
Now that we have a Gulp task that will start everything. Let's make sure we get rid of our hard coded port number here in app.js. We'll come back over in our Gulp file. Let's add in some events that we can track what's going on. So at the bottom of this, we can chain onto this nodemon process a few event handlers. They can say on and then the first one we're going to do is restart. And then it's going to run a function. So we can reuse this code here, because there's actually a few events that we're going to track just to show how they work. So we'll copy and paste, and make sure we get our semicolon at the end. And the second event's not going to restart, it's going to be start. There's also an event called crash and one called exit. So let's put a few logging statements inside of each one of these just so we can see what's happening. So restart's going to restart whenever files have changed on the server. So we'll put that in here. Now, it also has an event argument that passes in, will tell you what files have changed. And that's going to be array of files. And then start is also going to have an event that we're going to fire off. So, when it first starts up, we'll just say, hey, nodemon started. Now, crash and exit are similar, but they happen under different circumstances, here. So a crash is going to tell us that a script crash for some reason inside of nodemon. So a crash is going to tell us that some script failed on nodemon and caused it to crash. And then exit, as you might imagine is just a clean exit. So something happened with Nodemon, and things just ended, and they ended well. So now, with those messages in there we can just see what's going on a little bit. Well let's try this out. We'll come back over here. Let's kill the server. We'll clear it out. Let's go into app.js just to make a few changes as we go. We'll run gul serve-dev and we can see things kick up. And now we can see nodemon started. That's the event that we had over here in the Gulp file that we ran. So come back to the app.js. All right, clear things out and we can watch the events. Now let's say I change my file. I just put it in a comment in there. And now it's going to run those. So we can see that nodemon restarted. And then we saw the files that changed, app.js. And then it exited cleanly, and then it started again. So let's make something fail a little bit. Let's go ahead and call express, foo. That's not going to work so well for us. So, we did that. And now it says it's restarting. It restarted, that was the file that changed, it exited, and then it started again, and then boom, when it restarted it crashed because it doesn't know what express is anymore. We're using it in code and we renamed the variable to foo, but notice it's still running. So I come back in here now, and I type in express the right way, press Save. We've restarted doing the changes, started, restarted, there's the file, and then we're good to go. So these events are really nice to watch what's actually happening in the background. One other thing we can do with the events, we'll come back over in to our Gulp file, is on a restart, maybe we want to run another task. So instead of a function, we could just call a task. Now we have a task called vet, which will run JS into JSCS. We'll scroll back up and we should be able to see that up here. And there she is. So if we come back down to our task and we run that here. Let's go ahead and kill the task over there. And then we'll restart just so you know everything's clean. And there's our start up. Notice it didn't run vet now it ran the basic inject task. And then let's clear this so we can see it all. Now let's go back into app.js, and let's just get rid of this comment. We'll press Save. Now it's going to analyze the source, and then it's going to go ahead and restart the server. And we still get our messages. So that's the added advantage of using gulp-nodemon, is you can actually plug in an additional task that you want to run. And if I want to remove that task, I can just come back into my code. And I can remove that task just by removing it out of here.
So in this module we saw we could simplify the development process by making it easier to start and restart our code. And Gulp nodemon which calls nodemon to restart the node server changes. And ultimately, we get it down to a very simple process to run our development code and then restart it.
Keeping Your Browser in Sync
Syncing the Browser
We're now building and serving the app using Gulp with the help of Nodemon. But we're still opening the browser and typing in the URL ourselves, and then we're hitting Refresh, when we have changes. It'd be great, if we could automate that. Well, we're already launching the server, but this module, we're going to cover how to launch the browser, too. Now, we also want to be able to restart the server, and the client with code changes. Right now, we're just doing on node changes but we want to do it when the client code changes too. And of course, it must be fast. So, let's jump right in.
The way we're going to launch the browser is by using a tool called BrowserSync. Now, we can watch those files using BrowserSync, and then it'll automatically inject those file changes for us into that browser. And it has some cool features called ghost mode, where it'll synchronize actions across multiple browsers. Things like Click actions, and Forms, and Locations, and Scroll. We'll take a closer look at that. And we'll also take a close look at one of the modes that it has for injecting the files. For example, when a files change, you might want to reload the entire browser with those changes. Maybe it's Java Script change or if it's just CSS, maybe we just want to inject just that one file. And as you might have guessed, BrowserSync using socket.io to do this. And not only does it work in all the browsers, but it will also keep all these different types of Browsers in Sync, so we can open up Firefox and Chrome. And then as you scroll in one the other will scroll too. This is really handy for testing, how your application behaves in multiple browsers. Now, how do you set up BrowserSync? Here's an example of once, we require browser-sync, what we can do. Now, we can proxy the port where the app is being served into another port, like 3000. We can tell it which files to watch. In this case of saying everything under client. And we'll want to think with that file setting a little bit to make sure we get the right files. And the ghostMode is a way to synchronize between the different browsers. InjectChanges is a setting that defaults to true and if it can will try to inject just the file that had to change. And then the reloadDelay is how long do you want to wait before you actually do that reload? Overall, browser-sync will do for us is Sync browser when any file change. Now that we understand the tool let's go, put it to use.
Injecting CSS From Less
Connecting browser-sync and nodemon
Now we're restarting whenever client code changes, but what about that Nodemon stuff we did? One of the cool things about Gulp is it makes it easy for us to integrate multiple tasks. So, let's take a look at what that means here. If we go back up to our serve-dev, right up here,. We now see that we are kicking off BrowserSynch whenever Nodemon starts, but what happens if Nodemon restarts, what do we want to do? We don't actually, want to re kick off start BrowserSynch, we want to make sure that it reloads itself, so there's a subtle way that we can do that here and what I like to do is I actually like to take advantage of a setTimeout, so on a delay, we are actually going to kick off BrowserSynch to reload itself. Now why a delay? Well, because nodemod might take a moment for the files to actually restart on the server and then we want to kick off BrowserSync. So, we want to give the browser enough time to restart, itself. So I'm going to put that as a configuration setting, and I'll call that browserReloadDelay. It's not the BrowserSync delay it's the reload delay. So, we'll come back into our gulp.config and we'll set that up down here. And that'll work really well for our application because we don't have much to reload. So, we go back over to the gulpfile. And we're kicking him off after that second. Now, what's that function going to do? That's the key. So, BrowserSync has some other functions that are built into it. And one of them is notify. So, we can kick off a new notify message here telling that we are reloading, so we can say okay, we are reloading now. And then another BrowserSync function which will tell to go ahead and reload. So, it will tell to reload and we don't really want to use the streams on here but it is, so you would actually will pull back Gulp stream if you wanted to. One of the options is to stream, so that's a true. So, in this case, we're really not taking advantage of the Gulp streams because we're just kicking off Nodemon. And we're saying, BrowserSync, go ahead, notify, and then reload. And it notifies that little message in the upper right-hand corner but wait for 1 second. That's because we want to make sure the file changes actually restart on the server. So, now if we test this out. We come back over here. Let's Gulp serve-dev. Let it load up in a page. That's great. We'll kill the old one there. And now let's go over here and let's find app.js. That's our server for Node. Now, if I put a space in there, and I hit Save, it's going to restart the server, and then it'll restart BrowserSync.
Synchronizing Multiple Browsers
Well, let's say, you didn't always want to do this. There's another option we have. We'll kill our server. And that is, to come inside of your gulpfile, and we'll set a nosync option. Now, this is really easy to do. What we just want to do is go back down to our start BrowserSync, and not only check if it's active. But if somebody passes in an arc called, nosync, then we'll just get out of here. And we already set up ours at the top and that's using the yargs commands. So, let's go back over here and now if we type in Gulp serve-dev and we do no sync, it should crank up the server but not do anything with BrowserSync, which is exactly what we want in that case. Now, I can go ahead and get rid of that and if i type it in, it will crank it up and open up BrowserSync. So, by default, I turn it on, and I make somebody actually type in nosync to not use it. And the last thing that's really cool to look at here is let's go ahead and open up Firefox. And we'll crank that onto this side of the screen. And let's, we'll open it up on this side and on that side. So, now we have Firefox loaded and we've got Chrome loaded. And let's try to make this a little bit easier to see everything. There'll be a little bit on this one. We'll do that one over here, and we'll make it a little bit smaller, and now we can see multiple browsers going on, so when I make a change over here on this side, we'll go into the dashboard controller. And, let's just go ahead and change dashboard to make a Dashboard for 1, 2, 3. We press Save. Both browsers were updating. Now, another cool feature, let's get rid of that, so we don't forget. Another cool feature here, we'll put one on one side and one on the other, is as I scroll on one, notice the other one scrolls. Now, that's pretty cool. And if I click on somebody like Harry Potter over here, it's going to go and look at the same one from this one. That one had a different first person, so it's going to go to that page there, too. And that's what ghost mode does inside of BrowserSync.
Building Assets and Keeping Organized
Now that we have a great dev process, let's make sure we have our distribution folder, our build folder, ready to go. And that's going to mimic basically what we roll out to production. The first task, course, to create a build folder itself. Now we're starting to get into having a lot of tasks, so we want to add some things to the Gulp file to make it easier to maintain. Then we'll establish our build folder and then we're going to handle compressing our images and moving them to that build folder, and then also taking care of our fonts. So let's dig in.
Task Listings, Image Compression, and Copying
The first thing we're going to do is add a new way to get a list of all of our tasks. So we can basically type in Gulp, and then we can see all the tasks that we've already created. This is often helpful because maybe you don't remember the exact name of the task. And to make this happen, we're going to use the gulp-task-listing task. And then we'll also define a task called help, so we can type Gulp help. Or we can just do it to the default task, and that's in task named default. And that's a special task where if you just type in Gulp with no name after it, it'll actually call this. So that's really helpful where nobody knows what the names of your tasks are. You can just type Gulp. And therefore, instead of writing some default tasks that may be like compiling your code, or doing some image optimization, maybe it's something else entirely. Now when they just type in Gulp they just get a list of all the tasks that are available, and I find that especially helpful. And then once we have that, we're going to take care of handling our fonts and our images. So we're going to have a very short stream in this case. We're going to copy things, and the great thing about Gulp is we don't need any extra plugins to do this. It's built-in. So we'll take things in from the stream, in this case it'll be our fonts, and then we'll output the stream to a destination using gulp.dest. And there's going to be no plugin required here. Super simple. And then how are we going to handle a compression of images? Well, not only are we going to copy them, but first we're going to grab them and then, we're going to use Imagemin, which is a plugin. We're going to take all the images and then compress those, and we can set, adjust the optimization levels as we'd like to. And if you want to add extra plugins in there to handle different kinds of image processing, you can do that, too. And you can learn more about that plugin here, at Imagemin. And of course, where are we going to put all these things? In a build folder. So let's go take care of these tasks.
Creating Task Listing
To start things off, let's make sure we go get the packages using npm. Now we're going to want to make sure we save these again as dev packages. And the first is going to be gulp-task-listing. And we'll get the second one while we're here, and that is gulp-imagemin. And once we pull those in, we'll verify they're there inside of our package JSON. So I'll open that file up, and we should see them appear once they fall down from the internet. Now, the Gulp task listing is going to help us create the list of tasks in our project, and we're going to create a task in there, and we're going to call it help, and we'll also assign the name default to it. And now we can see once it's completed, they show up in package JSON. So we'll close him out of here. So we'll flip back over to our Gulp file, and let's add the task in here. And we're going to call this task help. And then in this one, we're only going to have one thing to run and that's going to be a function. And since that function is simply just going to be the task listing plugin itself, we'll just run it like this. What I mean by that is we could've written it out like this, where we had a function wrapper, or anonymous function. And then we call this, and we do it like that, but because we're not actually using anything other than task listing, it's just a little bit more concise to type it the way I've got it here in line nine. So that's the way I prefer to do it for that one. And then we can flip over here and now we can type in Gulp, what? Gulp help. And we can see all the tasks that we've defined. We can also any tasks that are defined as subtasks somewhere, as well. All right. Well, that doesn't solve the problem though, if I type in Gulp, what's going to happen? That's going to say there is no default task in your gulpfile. Well, let's solve that. Some people like to make their default task something that's going to build their code or write their development stuff, and that's perfectly fine. But here's an alternative that I've been getting really familiar with. And that's to name my default task which is the one that's going to run when you run just Gulp. And then have that guy literally just depend upon help. It's a great way to make a quick easy alias. So now when I run either one of those, now I just type in Gulp at the bottom, it's going to run help for me.
We want to make sure that the fonts that we're using, which come from Font Awesome and are located in the bower components folder, can be pulled out of there and put into a build folder. So let's do that now in a step. We'll come down right below styles. And let's add a new step down here called task fonts. So once we have that task in place, we can pipe in the source of the fonts and for now, we'll just say in here okay, return out the Gulp source. And since we don't know the source yet, we'll go look that up. We're going to create a config property for this and that'll be all the fonts. So that could be a glob that points to one or more of those. And then, we're going to have to send it out to a destination. So we'll pipe that out using Gulp destination. And then again we'll have to create some variable for where is that build location. And then inside of the build folder that we'll create, maybe we'll do it at /build, we'll have a fonts folder. I like, when I create a build folder, to have all my fonts and images and styles in different folders inside of there. It just makes it easier to handle the build pipeline. And I like to always start out every task with a logging statement. In this case, we are just going to be copying our fonts. Now we don't have fonts or build from the config so let's open up our Gulp config and add those there. First let's add our build folder. We're going to reuse this quite often, and I'm going to choose to put this folder in a ./build. Now some people also like to do something like this. You will see this very common as a dist folder for distribution. Sometimes you'll see one called production or you'll see prod. It really doesn't matter where you put it. It's really up to you. In this case I want it to be in build because that's where my node server's going to be serving it from. And if you want to see that quickly, we'll flip over to the app JS file. We'll see down here that if we pass in, that it's in Build mode it's actually going to be serving out of the build folder. Notice when I'm in Dev mode I'm serving from the client folder, from the root, from temp, all over the place because that's Dev mode. That'll never go to production, but at production I serve out of this one folder. So coming back in here, we've got the fonts that will end up in the build folder but we need to know where did they start from. So keeping this somewhat alphabetical, we have to put in our fonts here. I happen to know these start out in the Bauer components folder, and then inside it is a Font Awesome file, and then inside of there, there's fonts and it will grab everything that happens to be in there. So now we've got our source and our destination, and if we want to come back over into terminal now we can run Gulp fonts. And if we look over on the left after this runs we should see a build folder, which we do, and inside here should be a fonts folder and then our fonts from Font Awesome should appear. And voila, there they are.
Now let's create a task for handling our images. So we'll create another Gulp task in here and we'll call this one images. And first we'll put a logging statement up here to say hey, we're copying the images. Now we can probably copy this logic up here. Let's do that. And always be carefree with copy and paste. So we're copying him. Now it's not going to be the fonts we're grabbing, it's going to be the images, so we'll have to go create that. And we're still going to use the build folder, but we're going to put it in a folder called images underneath there. Now we're not just copying, though. We're going to be copying the images and compressing them. And that's an important step in the build to make sure we reduce any size that we don't need, so web pages are a little bit more responsive. So we're going to pipe in the new plugin that we pulled down, which was Imagemin. Now Imagemin has a bunch of default options but it's also got one we can override that I like to do. Now by default, the optimization level is 3, but we'll go ahead and specify 4. Now let's go back and add the config images, which is what we have here in line 47. We'll pop into our Gulp file for our config. And we'll pop in the images. Now all of our images are going to be in a folder called images under the client folder. And we want to grab every single one of those that happens to be under there. So we start off with not just images, but with client, and then I'll make sure we grab them all, and we could do like .png or .jpeg. We might have a variety, so I like to grab all of these. We come back here and we've got our images there. So now, let's go back over here and let's run our images command. We'll do Gulp images. It's going to compress them, and that should move them over into the build folder. So now under build, we have fonts. And if we look down below, we also have images. And there they are. And you've got also the sub folders where we had a bunch of photos.
I like to make sure when I'm creating a build task that I clean out the build folder before each of the tasks. So we already have a clean styles. I'd like to reuse this, and let's make one for fonts, and one for images. So we'll change this first one up here to be fonts. We'll keep it somewhat alphabetical, and then images. And then here, the fonts aren't going to be located in temp. They're going to be in the build folder. So we're going to want to clear that out. And then we're going to find everything in here that's under fonts. And then we'll just do star.star. Now do we really need this variable here? Not really. So let's just pull that out. And we'll put it right in place and make this guy a one-liner. Now we do the same thing for images. So let's copy and paste again. Now we got clean with a config build, that's where they're located, and then it's going to be images. Now notice we have three clean tasks here. We've got one for styles, one for the fonts, and one for the images. And we'll pull this guy off as well into the files. Now they're running three separate ones, and that may seem like it's a little silly at times. Why not just clean everything? And there may be a use case for that. But it's really helpful to have one for each individual task so that when I run just images, I'm not wiping out the fonts and the styles too. So I like to have an individual task for each of those, all calling that function that we have. However, let's create a single task that just does a clean as well. And it gets rid of everything. And I usually I don't put that in the CI process, but if I do a clean everything, that's going to clean out everything for me and it's something I can manually handle. So on this one, I will create a variable, because I want to clean a couple of different folders. And I'll call this okay, go get my delete configuration. And then I use just the array concatenate function that concatenate a couple different things together. So first one's config build. Get everything out of there and get everything out of config temp. And the reason I use the concat function on the array is it'll take in a string or an array and concatenate them into the array for me, whereas, push will only push individual objects in. So this way, whether temp or build is a string or array, I don't really care. It's going to merge them all into a single array, which is what I want. Now this time, I'm not actually going to use the clean function. I'm actually going to tell it to go ahead and just delete what's in the delete config. And then when I'm done, call done and I'm going to do a special log message in this case to say what am I getting rid of? So in this case I am going to be cleaning, then what, let's just list out all of the folders. So I can do that here is use utils and we'll put the paths in a special color, and there we go. So let's test all of these out. First, let's make sure that our clean for single one, let's say fonts works. So let's run Gulp, clean fonts. Over on the left before I type that in you should be able to see the fonts should disappear. So let's open up these folders. And there we go. There's our fonts and there's our images. I run that and the font should disappear, and they do. So let's go ahead and try to create a little bit more going on here, so we'll do gulp fonts, and then we'll type in Gulp, and I think we have a styles task. Right? Let's make sure we've got him. The name of that is styles. We'll do that. And if we click up here to temp, we should see that guy in here. And there he is. Now let's try running Gulp clean, and it should get rid of everything. And notice it got rid of the build folder and the temp folder. So one of the things we'd like to do, now that these different tasks work, is before I run fonts, I should make this dependent upon the clean fonts. And likewise, I want to do the same thing for the images here. So that means before you run fonts, clean it out. Before you run images clean it out, and we want to do the same thing with the styles. So now if we run one of those tasks over here, let's go ahead and create our styles with Gulp styles. We can see it appears in the temp, and here it is. And now we come back over here and let's run Gulp styles again. You'll see it cleans it out and then puts it back in. And we can see that up here, it's cleaning out temp, and then it compiled it and we see the file right there. It's just a nice way to tidy up after ourselves, or before we get moving.
Gulp makes it easy for us to copy files from one place to the other. So it's got that built-in copy where we go just use this source and send to this destination. And it's great for creating a build folder. We also took advantage of the gulp-task-listing plugin that lets us show all the different tasks in our Gulp file. And I like to do that because it just helps me organize them. And then we used gulp-imagemin to help handle image compression, and then we passed those off into the build folder. So now that we have a build folder, we have some other steps that we want to do when we actually create a production build. Let's take a look at those.
Caching HTML Templates for Angular
Caching HTML Templates
When building an Angular app, it can positively impact the performance of the application if you use the template cache to reduce the HTTP calls. So in this module, we'll cover just how to do that. The way HTML templates work in Angular is right off the bat, you're going to have a lot of templates that you may calls for over HXR. XML HTTP requests. But instead of doing that, we're going to cache the HTML using Angular and it's going to reduce those requests, and it's going to do that using the $templateCache service. So let's take the next step in creating our production build pipeline using Gulp by integrating with $templateCache.
Angular's Template Cache
If you are building an Angular application, this is an important step in your build pipeline. Because everything that is a template or an HTML Template more specifically is going to make a call across the network, unless we use $templateCache. And these are used for things like directives, because they have templates inside of Angular and so do routes. And it's really anywhere that we call HTML over URL from Angular. The first time it needs it, it's going to go across the wire to say, hey, let's go get that HTML and pulls it back into the app and then it'll cache it on its own or we can warm up the cache. And the way we do that is through the $templateCache service. It's basically just a key value pair, which allows us to create this $templateCache put. So we say in here, all right. There's the key and that's going to be the URL of where the HTML's located and the second value is the value for that. So when your directive or your route is looking for app/layout/ht-top-nav.html, instead of making a URL call. The first thing it does is looks inside the $templateCache and says, oh yeah, I've already got that. So let's take a look at a template that could take advantage of this. Here we have a simple directive called htTopNav and notice that we've got a template URL down at the bottom. If we do nothing else, the first time this app runs, it's going to see this line of code and make an HTTP request to get that HTML. And its exact process is first, it's going to look at $templateCache and then it'll make that HTTP request. But again, we're going to try to warm it up. So, it finds it on that first look in $templateCache. Now we can do all this manually or we could take advantage of Gulp. There's a plugin Gulp called gulp-angular-templatecache and it's going to gather all the templates using Gulp in our pipeline. We're then going to minify the HTML, because why not? It just makes it smaller and faster and come across as wire. And then we're going to add them all to $templateCache using their keys for URLs and the values will be the HTML. And we'll put them into an Angular module and then include them in our application. And we're doing this, so we can reduce all those extra HTTP calls across the wire. So let's go do that.
Cleaning the Built Code Folder
Minifying HTML and Putting in $templateCache
In this module, we took the next step and creating a build pipeline for our production code. We reduced the HTTP requests for HTML templates using angular-templatecache. And to do this, we used Gulp with the minify HTML and the angular-templatecache plugins. And that generated a templates.js, which had the templateCache puts statements in it. Which is going to be added to our application to handle the template caching and this gives us an optimized way to run our application. So you can see a build pipeline can not only make developer's life more efficient, but it can also make your production build produce a more efficient app.
Creating a Production Build Pipeline
Optimized Production Build Pipelines
Serving code in a development environment versus a production environment is very different. We want to have an optimized build pipeline for when we're serving to production. So this module is going to cover how we can get a build out. This includes things like images and fonts, the template cache we just created, using HTML injection, Bower, wiredep, and more. We're going to be grabbing all the files using useref, that's a plugin for gulp, and using injection. And we're going to move all that stuff out to a build folder which will create the optimized files. And of course, we'll be updating the index.html to point to all these new files.
Creating the Optimize Gulp Task With Template Cache
Well let's start by creating our optimize task and that's going to be where our build pipeline all gets put together. And he should depend upon, and make sure we run, inject first. Now let's do a little bit of logging here to make sure we can say, all right, at this point now what we're doing is we're going to optimize all those files. And then we're going to create our gulp pipeline. We'll feed in the source and we'll tell the source it's going to be our index.html file. We have one of those already over inside our gulp config. We can take a quick look. And he's right here on line 21. Now once we feed in that file, we'll make sure we've got a little bit of error handling in place, and we'll use plumber to do that. And then we'll have a TODO here for processing our files, because there are going to be a lot of little things we're going to add under there. And then we're going to make sure we pipe out the files to our destination, which will be the build folder. So what is one of the things we might want to do in here? Well, let's first start with the task we just finished in the last chapter and that is the template cache. So we want to get the template cache js file, which is templates.js,and put it into here. So we'll use inject to do that, which we already have. Now, we want to make sure that when we run inject, it also runs template cache. So now, by the time it gets to optimize, it'll already be ready. And then we're going to pick that file up here and we're going to inject it into the HTML. So to do that, we already have a plugin called gulp-inject and it's going to tell that to read the source for the template cache file. So we'll create a templateCache variable right here. We'll come up here real quick and we'll leave a space for him. And then the second parameter of this is going to be okay, we want to make sure we're reading false. And the third parameter is going to be, what tag are we going to be looking for in our index.html file. So that's an easy one to solve because we can actually go over and look and see what's there inside of index.html. We can see we have this injecttemplates:js. We can copy that, and bring it back to our gulp file, and inside the start tag, we can stick that in here and surround that with the appropriate HTML comments. And then make sure we get the right parentheses in here. In our template cache, we're going to tell it, go look inside the temp folder, and then find my config templateCache file. And remember, if we go back to our Gulp file, we can see those down here. There's our templateCache, and then the file, which is templates.js. So what does all that mean? That means we're going to look for the templateCache file, not going to read it, and we're going to then find the, in the index.html, this particular comment, and then replace and inject that inside of there. So ultimately inside the index.html, when we run this, we should see that appear in this right there. So, let's go ahead and run this and see what happens. We'll come over here and run gulp optimize. And then it ran everything. Now if we flip back over to our code, look in the index.html, scroll to the bottom. And this is the source one. We see nothing here. And we look over in the build folder and there's an index.html. And notice down at the bottom, here we have our templates.js. So that's the first step in cyber pipeline.
Adding gulp-useref to the Optimization Pipeline
Cleaning and Serving the Built Code
Serving the Optimized Build
We just saw how we could create the beginnings of an optimized build pipeline using our index.html. We prepared the source index.html so we could create a build version of that. And we use injection to handle things like templates.js. And then we use use-ref to parse those comments, so we can concatenate and gather all those assets. And then write them out to the build folder, and change the script tags in the destination index.html to point to those. And then finally, we served up the code using node. There's much more we can do. We're going to be taking a look over the next few modules.
Minifying and Filtering
Minifying and Filtering
Serving Optimized Code
When Optimized Code Fails
Foreshadowing of the Effect of Mangling on Angular
Angular Dependency Injections
Angular Dependency Injections
We just learned how to optimize our code using and Gulp. And when building Angular applications, there's a couple things you have to take into consideration. One of those is handling dependency injection. Now it's Angular in this case, but this is a great example of how we can use Gulp, and its build pipeline to modify our source code in its destination folder. Not the direct source, but the one we're putting in the distribution folder, or our build folder. So really we're going to protect our code using Gulp because when we mangle our code it's going to rename some of the variables. And we do want mangling because it's going to save a lot of space in our files. It'll make them smaller. And Angular uses variable names and does service location to find the dependency injected variables, things like our services, for like data services or controllers. And we can write manual injections to solve this, but we can also cover ourselves, a little insurance, using automated injection. So in this module, let's learn how we can use the Gulp pipeline to handle this automatically for us.
Mangling and gulp-ng-annotate
When we optimized our code, we saw that the code ended up getting mangled where the variables got renamed. Notice here in the example we had $state, which then became let's say d, and then dataservice was e, and logger f. And then the controller, Dashboard, became u. It all gets mangled and that's what the mangling process does. Now, we want that to happen because again, it shrinks down our files. But this causes a problem with Angular because it can't locate state, dataservice, or logger, so when you run the code in its mangled state, we may get errors. Now there's a couple ways we can handle this. One is you want to write the code with manual injections inside of Angular. And if you take a look at this hyperlink here, you can check out my style guide where I show ways you can do that. But we can also use Gulp to provide a security blanket. So let's talk about how we can add Angular's dependency injection annotations through the Gulp process. Now we can pull down the gulp-ng-annotate plug-in and install that into our pipeline, so that will search for any place that needs to pass the injection. And it will add it unless it's already there. So it's smart enough to see if it already finds the same thing. So it won't duplicate it, and we've got a couple of options that we can use to customize how it should behave. Now there's really two plug-ins in play here. Like with most Gulp plug-ins, there's a base plug-in which operates under node and then there is the Gulp plug-in which is the partner to it. So the base plug-in is ng-annotate. That basically just runs on top of node and allows you to run through files, and then add these annotations. And then there is a gulp-ng-annotate which uses that plug-in as a dependency, it doesn't rewrite it. It uses that plug-in and then adds in the Gulp streams and puts a few features in there to make it work with a Gulp pipeline. So let's take a look at some of the key options that we can use inside of ng-annotate. The first one is add, where basically we can say signify true if we want to add the annotation to the files. We can also signify remove if we want to go through files and remove any annotations. And there's also an option for single quotes. You can set that to true or false to basically tell it when it runs through there any place it sees an annotation, use single quotes or double quotes. Now that we understand how ng-annotate will work, let's go ahead and add it to our Gulp pipeline.
Adding ng-annotate to the Optimization Task
Now to show the true value of ng-annotate, let's take a closer look at an example which is easy to miss in our code. So inside the config.js file inside the Angular application, we've got this resolveAlways command which is going to run a ready function, which is right down here on line 49. Now that function works fine and we've got the inject statement in there and everything. But there's another way to write this resolver. And that is instead of actually having a named function there, we can just write the function like this, without the name and make it anonymous. Now that still will work when we run without mangling or minifying. Let's just comment this code out for now. But when we run this code and mangle it, what's going to happen? Let's think about this for a minute. This function is going to get dataservice minified or mangled to like d, or f, or x, or some other letter. And it's not going to find that letter, it doesn't know what that thing is. So we need a way to put an injection in there. So even with ng-annotate, let's go ahead and see what happens when we do this. So let's go run this through our optimize process and see what happens. And here we go. It's optimizing the file, and then it'll stick it inside the build folder. So let's run and look at the code inside the build folder. And then we're going to find the app.js file. And now, so we know what we're looking for. Let's come back to the code. We're looking for this resolveAlways with a ready. And it's got a dataservice ready. First of all, if we look for a ready function, are we going to find one? The side bar ready and there's our ready function inside that config. Notice that's the ready and then it says calling function t so, I guessed it was d or e but it's going to be a t. And then over here in the actual code notice it's supposed to be dataservice. So that's going to be a problem and notice it didn't put an inject statement in there because it didn't know how to do that. So this is where we can give it a little bit of a helper. If we go back into our source code, let's go ahead and give it a hint here. So now we're saying, all right, something inside this object literal is going to need dependency injection. So ng-annotate is going to need a little help. We're going to do that for it. Let's close down our app.js. And we'll come back over, we'll run the optimize task once again without making any code changes to the Gulp file whatsoever. And then when it's done, let's see what happens. So I'll pop back in to app.js and let's search for the word ready once more here. Now we find t ready, but notice right before that we've got a t ready right up here, where the ready is saying, okay, I'm going to wrap you inside of an array. So that array contains "dataservice" and then the function that defines t. So it's actually going to help add the injection for us. So we can see that we can actually do this kind of stuff. We have embedded functions that have dependency injection in Angular by using this common syntax. Now, another way to solve that is to use named functions, which is another preferred route I like to go with. So if we take this route here, we get back to the original state, where we're saying ready is there. And now, we don't actually need this comment. It's helpful to leave it there if you'd like to, but it'll find it either way. And then now, we've got the manual inject statement in there. So that's one way that we can actually give a little bit of help to the Gulp ng-annotate plug-in. And if we go back over to the Gulp file, there are some options in here too that we can take a look at. One of those is going to be true. Now true is we want to make sure that it adds those options. If we wanted to strip them out of the files, for some reason we want to take a look at the code without the annotations, we could put true and therefore remove. Now, sometimes I just want to be explicit, so I'll say add true just so I can see that in the code, but that is the default as well, so we can remove that. And one last thing to clean up here. I like to make sure that all my configuration is over inside the gulpconfig. So I don't really like saying lib.js is here and knowing that that matches up against what's inside of my index HTML. So instead of doing it this way, I'd like to go ahead and grab the gulpconfig file. That's over here in our bar. And then we can add an item to the gulpconfig for managing those file names. So, down below temp let's add another section here for optimized file names. And there we go. And let's call this section optimized. Now, the first one we're going to add is going to be for the lib and the other one's for the app, right? So let's say lib is in here. Now, it's going to be lib.js. We may want to name this something different. So it's helpful to do these kind of things. And now, if we ever want to change them, they're all in one place, in one file. So, how do we refer to those? We just go back to our Gulp file. And instead of referring to it as app, or lib directly, in hardcoding these strings, now we can come up here, and we can put that in place. And then we can say, all right, go to our config, and then look up the optimized. And in this case we have app or lib. And we can do the same thing here with our application.
Static Asset Revisions and Version Bumping
Revisions and Versions
Once you have an optimized build pipeline, the next step is to actually roll your code out to production. So in this module, we'll talk about a couple things we need to do including handling static asset revisions and how we can increment versions or bumping. And the key to asset revisions is you want a pretty unique file name so your production index.html file that serves all your code has a unique file so you can avoid unintentional caching. Sometimes, this is also known as cache busting. So we're going to create file name revisions that make sure we can load the new file when we have new code. And we'll be using a hash sequence to do that. And then we'll also be incrementing the package for our package.json in our code using sever. So let's round out our optimization and add these features.
Exploring File Revisions
Let's start by adding file revisions into the Gulp build pipeline. And we'll be using a plugin called gulp-rev. And you can learn more about that plugin here, and basically, it's got a simple function, it's going to rename the file with the revisions using a content hash. For example, we might have app.js and that gets renamed to app-, then some hash, .js. And then we'll use another plugin called gulp-rev-replace, which works in tandem with gulp-rev. And this plugin is going to rewrite any of the occurrences of those file names that we just rewrote from gulp-rev. For example, inside of our index.html, we're going to want to make sure that we pick up that new file name. So we're not pointing to app.js anymore, we instead were pointing to app-, then the hashcode, .js. And the reason for doing this is, if we don't do it, think about what happens. Every time we have our new release, we have app.js and live.js. And the code's put out there if somebody's caching those files in their browser. Even if we have new version of it, it's not going to automatically go get the new version. How does it know? So I replace in the entire file name based on a content hash. We know we have a completely different file, index.html's pointing to a new file. And now we're pointing to a completely different file back on the server. So this is one way we can force a reload and not worry about having to cache a file because the whole file name is different. Of course, you may also want to set the expires header, too to some kind of far out date. Well let's go add this to the pipeline.
Adding Static Asset Revisions and Replacements
Generating a Revision Manifest
Now if we want to know what the from and the to was for the file names, the old name and the new name, we can also write those out into a manifest file. So down here, let's go ahead and change this pipeline just a little bit. We'll add another build, so we'll write things out as we need to. And then, let's go ahead and write out a manifest. And it's a feature hanging off of rev, and it's called manifest. So after we write the files out, then we're going to create the manifest, and then write that in the build folder, too, just so we can take a look at this. So, once again, let's run the same task. It's not a new plugin, it's the same plugin that we've had. And now, once that plugin is running, we should get a manifest file in the build folder, where we can see the old file and the new file. And you could use this for any further processing that you might want to run. See here we can see rev-manifest and is a JSON file and it shows you the old value and the new value. And this can be helpful if you have to do any custom processing, where you need to look up what was that value and then modify files manually or through some other Gulp task.
Bumping Versions With Server
Now that we have our build all optimized, maybe we want to make sure that we can increment our versions of the application inside of our package.json. So we open that up, we can see we've got 0.1.0. That's the major, the minor, and the patch. And that's what those three different numbers represent. Now, you can also have a prerelease, as well, where you say something like, okay, it's this one, but it's also going to be a beta. So we may want to update this at varying times based upon what the state of our code. Now it might seem like a minor thing to create an automated task to do this using Gulp, but it's actually quite important because I can't tell you how many times I've created open source software. I've done all my code changes, and you're so focused on that stuff. Then I release it and I forget to actually change the version number in one of these files, so then I have to do another version number upgrade just to get it out there. So let's not even have to worry about that stuff and let's create some kind of a Gulp task to do this. So down inside of our file, let's go ahead and create a new Gulp task called bump. And this is actually going to rely upon gulp-bump plugin. So let's go over inside of terminal and we'll install that. And this is a very simple plugin, which is going to help us with incrementing sever with that major, minor, patch and prerelease. Now let's create a message to log out. We're going to want to make sure we can log out what version we're actually bumping up from, so we'll put this together inside of a variable. And now we'll set in some input. So let's use a few comments here that we'll put in that will explain a little bit what we're trying to accomplish. So we want to make sure we can bump this version. So if we type in something from the command line, we may want to tell exactly the version we want. Like if I type --version equals 1.2.3, that should go right to that version. If I just type bump with pre as a type, it should update the prerelease. And then if I type type equals patch, it should update the patch version. So we want to make sure that we're doing this right. So we got to have the logic in place to do this and we have to accept in these arguments for both type and version. So we already have yargs, which is great for us, and that's in a variable called args here. We can scroll up to the top real quick and see that. Here on line two, there's our args. And we come back down to our bump task. So that's great. So we can capture the type here into a local variable called type. Now let's also accept in a version parameter. And we'll store that locally, too. So from the command line, somebody could type that in and we're all set. So first, if somebody passes in a version, we want to use that exact version. So if there's a version in here, let's run that logic first. In that case, we're going to set the options for bump to say, grab the version and put it on the options.version. Now what's this options thing? Well, we're going to need to have an options object that we can pass in, so we'll define that right here first. And if that's the case, we want our message to say, okay, we're bumping versions to this number. So, in this case, we'll just say, all right, message, take bumping versions and we'll stick on the message. Now if it's not a version, we want to make sure we use whatever they told us to use, whether it's patch or minor or major. In that case, we'll go ahead and get the options. And we'll set the type equal to whatever type that we pulled in. And then we'll update our message accordingly. And then we'll log out the message, and, of course, we've done, all we've done so far is accept in the input and get ourselves ready. Now we actually have to use Gulp to go ahead and bump it. Now, what are we going to bump? Well, let's set this up in configuration. So you might want to do just your Bower. You might want to just your NPM package.json. Or you might want to do both. So let's set that in configuration, so you can do that there as opposed to in this file. And then we'll call bump. And we'll pass through it the options. Then, finally, we'll write things out. And we're going to write it right to the root of our project. So we have a couple things we have to make sure we have. We've got config.packages, which config right here, and then we'll put that right below our Bower and NPM locations. We'll create packages here, and that's just going to be an array. And the first one of those packages is going to be in a root, and it's going to be package.json. And then we'll also do one for bower.json. We'll update both of them, why not? And the other we had was the config.root. So we come up here, we don't have a root yet. So we can create a local variable for that. And then we'll expose it down here. And now, if we go back to our gulpfile, we should have config root, and we've got config.packages. So we're good on both of those. So now, we should be able to call the bump task, and it'll increment accordingly. So we know, already, in package.json where we started, is 0.1.0. So let's go ahead and let's call bump. We'll say Gulp bump and let's just tell it to go to, let's say, type equals we'll do a minor. When I did that, it bumped it up to 0.2.0. Now just to make sure we've got this in place, we can go to package.json, we see it 0.2.0, and then over on our bower.json, let's take a look there. Now you might have seen two messages, and the reason we have two messages is it actually edited two files. So if we want to see which files it's actually happening to, one way to do that is we can pull in that good old package that we used earlier, the print. So we can put that in place. We can say, all right, go ahead and use print here. And make sure we get a dot and not a comma. And now let's go ahead and bump to minor again. This time, we can see it went to 0.3.0, but notice it's actually printing out the name of the file. Well let's test it out if you want to go to a specific version. Let's go ahead and type in version and let's tell it we want to go to version 2.3.4. And there we go. So let's go back and look inside of our package.json and just verify things worked, and they did. And we can also go backwards in our version. We'll set it to the original state, and we're back to 0.1.0. So this is a very simple way to create a way to increment your versions inside your packages.
We just rounded out our pipeline for the optimization task. And we did that by adding in the hash codes to the file names. So we pull in the same source of the index.html and perform all our pipeline tasks. And then we write it to the destination. And the keys here, we're using gulp-rev and gulp-rev-replace. And here we can see that we replaced the file names with these content hashes, and then we rewrote the occurrences of those file names using rev-replace. So, I like to use gulp-rev to help rename things and then rev-replace to replace them, and they work great together. And then we also used gulp-bump to help increment the versions inside of our package.json and bower.json. And that might be a simple task but I found it to be very valuable in helping me make sure I increment my versions properly.
Gulp is ideal for build automation tasks, as we've seen so far, but it's also great for handling automated testing. So, in this module we'll talk about different ways that we can handle testing using Gulp. One of the more obvious ones is to create an automated test runner. So, Gulp can handle setting up all of our tests and then running them through and letting us know if they pass or fail. We can also report on code coverage or even make sure that our tests are automatically running, while we're writing code. And then whenever we change files, it reruns those tests so we can see pass fail instantly. And some tests are unit tests where we're just testing one thing. And others are integration tests where we have to hit other components, maybe a backend server. There's some nuances to how to set up backend server tests. And we'll take a look at how Gulp can help us get there. And finally, sometimes you got thousands of tests and you don't actually want to see them in terminal, you want to see them under browser in a much more user-friendly interface. We'll take a look at how we can run them in a browser, and keep them in sync.
Karma and Single Run vs. Watching
Let's take a step back a moment, and first think about what we need to have a test runner. First, you have to have a project and you've got to have some tests. Well we can check both those boxes because we have a sample project, and we've also got some tests in it. And we also have Karma inside of our project. Karma's a very popular test runner that'll run a suite of tests for us. But how do we use Gulp to make this even easier, so we can hook all these up and run them in a variety of ways? That's what we're going to start exploring. So first a word about Karma. The way Karma works is it lets you hook up to multiple different kinds of testing frameworks, like QUnit, or my preference is Jasmine or Mocha, which are more behavioral driven. Jasmine and Mocha are very similar, but we're going to be using Mocha in this project. And there's a couple ways that become very obvious when you start getting the test runners, that you might want to run your test. One way is single run, and the other is like an always watching way. That's not a technical term, but that's exactly what it's doing, just, always watching your files. For example, you might want to use single run because it runs one time, and then it's done. You just want to run the test, see if they pass or fail, and maybe you fail a build on it. Which as you might have guessed is really great for continuous integration. Or if you just want a quick look to see, hey, do my tests work or not. But sometimes you're writing a lot of code and you want to keep running the test. Anytime there's a file change. So, this other mode that we can use is no single run. Which I call always watching. Let's you run and keep these things alive. So the tests will keep running, and any time a file change happens it'll re-run the tests. And the good news is it's really easy to change how these things work using Gulp. They can offer either one of these options using very similar code. So, let's go back into our gulp file. And let's code this up and see how it works.
Creating the First Test Task
Installing Packages and Running the Tests
Now, let's make sure we get all the packages installed for the project, and we'll check over our code. So inside your folder you're probably going to see an mpm-installs.txt file. This is a whole bunch of packages that we can install from node. Putting it over in terminal. And then we can hit that enter key and it'll go and get all those out of MPM. Now these are things like Karma, and Sign-on, and Mocha, and Phantom JS. All the fun stuff we need for testing our project. Now once that's installed, we can flip back over to our package JSON, and we should be able to see a whole bunch of Karma dashes in here, and then Mocha, and then Phantom, and Sign-on, and so on. So now that they're installed, we typed a lot of code, let's make sure we did things correctly. First of all, down here inside of our Karma options, we set up Bower files, we've got that guy up top. We've got config.spechelpers and config.serveringegrationspecs. Let's make sure we have those. So let's type that one in. And that's going to be an array. We'll start off by looking in the client folders, and we saw that this was in the test helpers folder. And it's all at the root level and it's just as files. Those are the files down here, bind-polyfill and mock-data. And we do have the server integration spec so we're good there. Continuing down we can see we've got the template cache file. We know we used that before so we have him. And we also have preprocessors which is always helpful to spell correctly. You need two s's in preprocessors. Because that's the file setting that Karma's going to be looking for. We can see that over in the Karma file right here on line 24. So that code looks pretty good, now let's go back to the Gulp file, now we run our task we want to make sure karma has got the right options here. This is interest config it's actually configFile, and single is actually going to be singleRun. So want to make sure you get those things correct. Those are the property settings for the options for Karma. Now once we have these we should be out of flip back over to terminal. And clear the screen up, and we should all type gulp first to see our test task show up on the list. And there it is. And then we could be able to run gulp test, because we set up that task. And it's going to run all those options that we just set up to run Karma against all of our unit tests. Now that ran pretty quick, notice we have 52 test running there. We actually excluded the server test. But now you can also see the code coverage down here at the bottom as well. So now we have our test running in single run mode, right here in terminal.
Making Tests Run Before Other Tasks
Now that we have the tests running, we want to make sure that they run before we actually optimize anything. So, let's go ahead and put that in this list here. So if we make a dependency of optimize actually be test then it's going to run a test before optimize. That's great but, maybe we want to do test earlier in the process. For example, I don't want to bother copying the fonts and images over if the test don't pass, it's just a waste of time. So let's create a new task up here, and find a way to work around this. And this task we'll called build. So build's going to do everything. Optimize will optimize the files themselves. But then build's also going to do some extra things like getting in the fonts and images. So it's just a way of breaking things up a little bit. So build will run optimize. And it'll have it run images and fonts. And that will be the build tab, so that means optimize no longer has to worry about taking care of fonts or images. So build sees optimize, which is in fonts, and says, okay, good. Let's go make sure that optimize is takeing care of inject and test. So if we just run optimize, we'll make sure that we're passing the test first before you run anything else. You don't really have to do this. It's just a way to show you how to break things up a little bit. So then, what would build do? Well, let's go ahead and make sure we're logging out that we're building everything. And then let's create a message. So in this message, we're going to pass it up there and log it out to the console. And we'll also do a little message that's a pop-up toast. So when it's done with everything we'll say, all right, we ran gulp build. And its got that title. Let's tell it what we actually did. We deployed to the build folder. And then finally, let's send a little message in there as well. We're saying okay, we're going to run gulp serve-build. So what are we going to do with this message? Well first, let's log it. Our little log method's going to handle that for us. And let's use notify to call that. Then when we're done if you'd like we can delete out the temporary folder. So it's telling us we don't know what this no notify is, and that's because we haven't written that function yet. So let's go down to the bottom down here, and we'll put it after change event. Create a function called notify. And he's going to accept in the message that we're passing, these are going to be the options, and we'll use a package called a node-notifier. And the options that we're going to use, we're going to make a sound of a bottle and then set up a little image of gulp, which is in our folder, and use that for an icon, so it'll just be a little toast in the upper hand corner. Now we have to assign those out and to do that we'll use a lodash function called assign. And we're going to take the notify options, and basically end up merging those with the options that we have. And we haven't pulled in lodash yet but we can get that. And we can use the notifier and call it's notify method. And pass in the notify options. Nofifier, notify notifier options. There we go. So we don't have path, and we don't have low dash, let's make sure we get both of those. So what are these two packages? We pulled in low dash here and we pulled in path. Let's go down here and find our code. Low dash is going to be a package that we're going to pull in from NPN. So let's go do that. We'll type in npm install lodash. Lodash is one of the most popular npm packages that you can pull down. It has a lot of useful functions in it for array manipulation and object settings, really cool stuff. It's definitely something I like to keep in my tool belt. Path, however, comes right out of the box for free, with Node. And that's going to help us do some path joining. And we're using that right here, where we path join, to go get the gulp.png. And we also need to make sure we get node-notifier. So let's go make sure we do that. We'll clear the screen. And then we've installed that package, as well. So now, we have everything we need to basically build it, and then call notify. But since we rearranged some of the tasks, let's go check those out real quick. We'll find optimize. And we can see that we've got the build task and the optimize task. We'll see if anybody else was referring to optimize. We are, over here at the Gulp watch, we'll be watching the last jobs within HTML. And then when those change, we'll run optimize. Which is good. We don't want it to hit the fonts or the images in that particular case. They've already been done. And that was the only place it was used besides build. Now build was one we just created, so if we go look up the serve build task, let's make sure he's using the right guy. Here, he was using optimize, we missed that one there and now he should be running build. Why? Because when we do a serve build, we want to make sure we build everything including the fonts and the images. So now let's go back over to our window. And let's type in serve build. So first it'll clean everything out for us and then do our js hint and js cs, and then it's going to run our test, and then we'll see our code coverage. And once it does that it'll continue on, handle the injection for us, and make sure we get everything over to the build folder. Launch in a browser, and we see our toast in the upper hand corner.
Continuously Running Tests During Development
We now have a task that'll run our test in a onetime pass, but what if we want to always watch our files and then run them again? So, to do that, let's go to new task called auto test and it'll still run vet in templatecache if you'd like, but this time for startTest we'll pass in false for single run. We don't want to run at once. We want to run it and then let it keep alive so we can keep watching our files. Let's come over here and we'll run gulp auto test. Now it's going to analyze our files. It's going to look at our template cache and then it's going to run our test. And notice the cursor just stays there blinking. I can kill it if I want with control C but I want to keep it running. So now let's try to run some code side by side here. And we'll try to make it a little more visible. And I'm going to go ahead and use my command shift O to open up a file. I'll go find my customers and it'll find the customer controller down here. And now let's go ahead and just put a couple spaces in there and we'll hit save. And let's notice it's watching and it re-runs everything under a hand sign for us. Then I can go get rid of those. And I can press save, and it's going to rerun those tests. So this is a great little trick, where you can keep terminal up and running on the right hand side or on another monitor, so you can code and watch your test run as you go. And then when you're done, you can flip back over here and just hit Ctrl+C and it kills out of there. So we're able to take advantage of how we wrote startTest as a function, and then reuse it from multiple tasks inside of our Gulp file.
We just saw how we could set up our testing inside of our project using Gulp and Karma. By installing all these packages, we were able to run all the Sinon and Chai and Phantom and Mocha things that we needed to do to get our test to work. And the key components in all these are Karma, our test runner, Mocha and Chai, which is our test framework and our assertion library, PhantomJS which is the headless browser which allows us to run the tests against the browser on a server, and then Sinon which is our stubbing and mocking framework. And if you want to learn more about how to set up these tests and different styles that you can use, you can check out some of the great courses here on Pluralsight. Or you check out some more information here at this reference at my angular style guide. So let's take a look back at what we learned so far. We learned about Karma and how to automate the test runner using Gulp and how to run our code coverage. And then we set up a watch so we could make sure we can run our test continuously. The next steps are to get back to the server integration test we talked about. And show us how they can run alternative test runners like running the text in the browser. And that will be coming up next.
Integration Testing and HTML Test Runners
We often need to test more than just unit tests. Sometimes we also need to test code that's actually hitting a back-end or server. So on this module, we'll talk about how we can set that up using most of the same code we already have. And how we can set up an alternative test runner using HTML. Now when you set up our server integration test, we're going to use the code that we wrote in the start test function. But we're going to crank up a second process inside of Gulp. And that second process will run the back-end server, so the test running the first process can hit the back-end server. And then run our tests and hopefully they all pass. And then, sometimes we don't want to run tests inside a terminal, we want to do it inside of a browser using HTML. So we're not going to use Karma, we'll use a browser to do this. Why do we do it? Well, it's just easier to read. So while running in terminal is great for quick checks or for doing a CI process. For a human, it's a lot easier to read inside of HTML where we've got some styling and we can actually see it easier. And by the end of this module, you'll set up your server integration tests. And create a test runner that shows in the browser that automatically syncs with any changes.
Node Child Processes
Let's take a closer look at what makes it different about running tests that require a server versus just plain, old unit tests. First, we're going to require a server, so Gulp is going to run those tests in one process. And then, we're going to need to crank up the server at the back-end with API, somewhere else. And we can use child process to do that. So once we have both those running we also have to make sure we're including our server specs. Right now, we've excluded those. And then, when we're done we need to make sure since we have two of these processes running. That when one shuts down that we shut down the other. So that's our quick checklist. And the key to this is going to be child_process, which comes with node. So we can crank up and require child process. And basically, fork off of that. And then, we can start the nodeServer that we've been using to run the application, itself. And give it a port to run on. And that's going to be ideal for running these kind of tests that require a back-end server. So we have all the tools we need to make this work. Let's go put it together.
Running Tests That Require a Node Server
Let's start by taking a look at why we're doing this. So over in our test folder, insert integration, we have one spec called data server spec. And inside of here you'll see that we're injecting the data service. We're not mocking it or stubbing it or anything. And that data service in our angular application is actually going to be making calls down to web API. So if we pull that file up, we can see he's using dollar $http, and he's going to be making calls down to like api/customer. Well, for that to work, there has to be something to talk to. So that's what we're trying to solve. So back in our Gulp file, we already had a start test function. We need to add functionality to this to handle running our tests that require a server. So all hinges on getting your child processed. So let's go head and create a variable for child. Now we've got child_process. Let's also create one for forking. You want to get the child_process itself and then we will create a fork off of that. And then the variable above that's actually going to be when we run this process. So now, let's move down a little bit. We need to determine if in command-line, we're trying to run those server tests or not. So we can go back to our good old friend, yargs. Now we've got that variable here, and we can use a command-line parameter, I'm going to choose to use startServers. So what that means is if somebody types in something like this, we're going to type in Gulp test --startServers. I want this particular code to run. And if they don't pass that in, well, it's not going to run it. So, of course, we're going to have an else condition, here, and part of our else is going to be to exclude those files. That's what we had before. Now if we get to this point, it's always good to log out of Message to let us know what's actually happening. Really just going to start a server. So let's go ahead and let's fork. And we'll give it the settings we had from our config.node server. And when we get the results of that, we'll set it to this child local variable. So what's that guy? Let's go back into Gulp config. We scroll up a little bit. And there we can see our nodeServer. So let's go back to our Gulp file. And we'll put a little bit of guard logic in here as well. So that if we don't have any serverSpecs, we're actually still going to be okay. So if there is a serverSpecs variable and it's actually an array with some kind of a length on it, then we'll be setting up the exclude files. So now we have the process running. We need to make sure we take it down gently. So this guy's gonna's run. And we're going to start Karma up. Karma's going to run the test for us. We'll have the exclude file set up appropriately. By default all those tests are included. Now when Karma's done it's going to run karmaCompleted. And if we're going to see if we have a child_process, we want to take some more action. So if there is a child_process, we want to shut this down. So we'll say child.kill. Yeah, it's a terrible name for a function. And we'll log down a message that's going to shut down the child_process. Now we set up a child_process, but we've got make sure that the ports and things are set up as well. So before we actually fork off of this, let's go ahead and set those. Here we're grabbing the process environment, and we're going to set it to be dev, because that's what we want for node. And then, we're going to change the port for these tests. That's going to allow the fork to go ahead and use these settings so we're not running on the same port. Now we should be able to flip over to our terminal, and let's first run Gulp test. Now make sure that our 52 tests run. You should be excluding the server test, and they do and everything worked. Now we should be able to run Gulp test --startServers. And this time it'll run all 55 tests that we have. Three extra ones that are actually hitting API. And notice it hit them all and it shut down properly. And we had a few extra log messages we should be able to locate in here. Notice at the end we see Karma completed and the we see shutting down the child_process. That came because we did the server process. So the node process that we forked and then created the child of, it got cranked up. And then, when Karma shut down we also shut him down, gracefully. So you can see it's not a lot of effort to make sure you can run both unit tests that require no back-end and cranking up another process in Node. In fact, we didn't have to use any Gulp specific plugins. We just used Node code to do that.
Setting Up an HTML Test Runner Task
Injecting the HTML
browser-sync and the Test Runner
You might be wondering why we're doing this work to set this up when you could just type this in yourself. Well, point of this here is first typing it in you might make a mistake. And a more important point is that when you add or remove files from your project, you don't have to worry about it anymore. So when you add your own code or Bower components, whatever it is, these are now handled by Gulp for you. But so far, we've just created the specs. Now let's create a task that's going to run the specs. So let's create a Gulp task called server specs. And this going to have to have a dependency of build specs because well, if the specs aren't there, it is not going to work. And we'll log out a message telling people that we are running the spec runner. And that we have a task called serve. And if you remember correctly, serve is actually going to serve up the code. We're going to take advantage of this. because it does a lot of the work that we need already. And the first parameter of this is going to be is it development or not. And this is a dev mode thing we're doing. And then second we're going to add a new parameter for hey this is the specRunner. Because it's probably going to be a few things different about serving the specRunner than serving the index.html. For example right off the bat we're not going to serve index.html we're going to serve specs.html. And then when it's done, we'll call the call back. So I'll put that up in the function up top. That way, if somebody depends upon serve specs it'll know when it's done. Now let's go find our serve function. Now notice we have one parameter up top. We already mentioned we want to add a second one here, and that's going to be the specRunner. Now the cool thing is our serve task is actually just running the node server. And then, what actually runs the browser for us is BrowserSync. So down here on line 264, we're going tell BrowserSync, hey yeah, it's inDev mode, but we're also going to have you run the specRunner too. So we're just passing this along. Now if we go look for our startBrowserSync we want to pass that in here. And let's look at what it's doing. So refreshing our memories here, browser sync is going to set up some watches to restart things. We're good there. But we also have some options down here, and all those options, do we want them the same for whether we're running tests or not? Sure, it's not going to hurt anybody. But there is a special configuration setting that we want to pass into BrowserSync,. And that's going to be the option to tell it what is the start path. So down here, let's go ahead and say if you're running the specRunner, we want to do a little bit of deviation. In this case, let's add on to the options. There's a start path that BrowserSync accepts. And we'll set this to be the specRunner file. Remember we have that specRunner file over here in our config, right there on line 81. So really all we did was tell BrowserSync to use this file instead of our index,html.
Launching the HTML Test Runner
Now we're just about ready to run. So let's flip over to terminal. And we're going to have a problem when we run this, but let's see what the problem actually is. We run Gulp serve-specs. It'll run through the process, and then it'll launch the browser. And we're going to get an error. It's telling us here. It doesn't know what this bard is not defined thing is. Well, it's looking for some file and they're not there. Well, brilliant, right? Well, the problem is, bard, if you go look inside of our project, happens to be a dependency that's in bower.json as a dev dependency. Notice we have dependencies in here, like jQuery and Angular and Bootstrap. And we have dev dependencies in our client project, this is in Bower, Angular, Mocks, Sign on and Bard. Now if we go back and look in specs.html, we scroll up to the top, and we look and see what Bower components got inserted. These are all the same components that were regular dependencies. We didn't pick up any of the dev dependencies. Now, let's pause for a moment, because this is an important point. With Bower we have dev and regular dependencies, just like we do with NPM, inside where package JSON. When we run the actual application, we only want the real dependencies. We don't want the dev ones. We don't want to load those in the browser normally. But because we're doing a special case here, we're creating an HTML test runner. We need those dev dependencies as well. So how do we get these three guys in the browser? So let's flip back over to a Gulp file and let's go find our build specs. And right here we've got wiredep. After we get the options for wiredep, we want to override one additional option. And the name of that option is dev dependencies. And we're going to set that to true. So now when you run this it should go get all of our normal options and then also include the dev dependencies. So let's flip back into terminal and we'll run Gulp serve.specs. We don't have to run build first because this will run build first. And it's going to run through the process. And now, we open up our specs and we get all the specs run in here. 52 passes and 0 failures. And notice you can scroll on down. Now the cool thing about this is we can see all the tests in one place. We can scroll and look through them, and we can actually click on the tests and see what was the expectation. Well let's go fail a test and see what happens. So if you flip back into our code, let's go open up customers controller. And it's got a spec right there. Let's just make this test totally fail. We'll actually change the test to do this. kind of a strange thing to do. But we'll say that this guy's got to equal customers, one, two, three, like that. Now, just by saving the file, I come back over here. It reran it already, because it's using browser sync. And I've got one failure. So I can scroll down and you're going to see exactly which test failed. Inside of that particular test that expectation for expected customers to equal this. But, that's a problem. So what's really cool is we're only seeing that little bit of error. Whereas we run the test in the terminal it's a lot harder to find it and make it a lot more text that gets spit out when there's a test failure. Let's take a look at that. If we kill this now, we go back into terminal. And let's kill that process. And we run Gulp test. Let's watch the test failure output. Just running through the same process. It's going to run the test. And now we get a lot more text and a whole stack trace that gets printed off. Now if you wanted that, that's great. But sometimes you want to just see, hey, what was the problem. So another technique that we can use is to use this kind of a test runner. Let me set my test back. So we run our test in the browser. We can see what is happening as it goes. So instead of having terminal open while we run our test to make changes and it re-runs them, now we can use BrowserSync and put this up. So as we're trying to enter code, we can move this off to another screen. And you can imagine you're sitting over here coding and we change something. And I'll again put some garbage in there, press save and automatically BrowserSync is showing us we have a failure. And we can see the exact property and issue that we lost.
Running Server Tests in the HTML Test Runner
So we're now able to run our test in the browser unit test runner and let's fix our test here. So we've got the right one, but we haven't yet run the server test in the browser. Now to make this happen, let's go ahead back inside of our Gulp file. After this dependency option, let's go set an additional flag here for, for passing in and accepting start-servers, what we should do. So let's think about what's different when we start the servers. We simply don't want to exclude the server specs. So let's create a local variable here called specs. And we'll pop up here and do that. And that's going to grab it from config.specs. And if we're starting the servers we'll say okay, go grab those and now let's concatenate some things together. Concatenate what was in specs and we'll go ahead and take what's in server and erase in specs and put those together. And then down below, we're actually using specs. So down here we were saying use config.specs to go always inject those. But now we're using a little bit of deviation up here with an if statement. So let's flip back over to our terminal. And let's run our server-specs. This time it should run just to 52 again. We'll make that full screen. We should see only those 52 tests. That's great. Let's kill this again. And now let's run it but with that extra flag. This should crank up the same browser, but run all 55 tests, those additional three ones that are running against the servers. We see 55 passes up here. And if we scroll down we should see at the bottom, our server data service, where it's actually going and checking and hitting the back-end. And by using BrowserSync, these will also refresh all these tests whenever we make code changes.
We just saw several ways in how to run our tests inside the browser, both for unit tests and ones that have to crank up a server. And to crank up a server is pretty easy. We just use Node's child_process. And we can run tests inside a terminal, which is great for CI or just a quick fix. Or if we want to make it a little more easy to read, we can do it inside the browser, using an HTML test runner. Which also hooks up to browser Sync so we can synchronize them, too. And again, if you'd like to learn more about testing techniques, you can check more information out here at this link.
Migrating to Gulp 4
Now let's take a first look at how we can get ready to migrate our code from Gulp 3 to Gulp 4 when it's released. We'll talk about some of the motivations that the Gulp authors had for creating Gulp 4, that's targeted to come out in 2015. And more specifically, we'll talk about the migration path and how we can move from 3 to 4. Because we want our Build Pipelines to work and there is a good migration story that we'll walk through. And the good news is we can take all the code we wrote in this course and in a few minutes we can have it ready to run in Gulp 4.
Tasks and Changes
Let's start by taking a look at the APIs that are the core ones in Gulp 4. And surprise, they're the same ones that we had learned in Gulp 3. There's task, source, destination, and watch. Now that doesn't mean there were no changes. The biggest change that's going to come in Gulp 4 is the new task engine. They switched out the orchestrator back end for the task engine and moved to Bach, another library. What does that mean to us though? There's a new function in Gulp called series. And you can pass in a set of functions or tasks and run those in a series, one after the other. And this is something that wasn't very easy to do in Gulp 3 because Gulp 3 ran everything in parallel as we've seen throughout this course. So above you can see an example of a styles task we write in Gulp 4. And now instead of a dependency array, we can say gulp.series run clean-styles, another task, and then run this function styles down below. So gulp.series accepts a set of tasks, which could be strings or functions. Now we didn't lose the parallelism, which is awesome because that allows us to run things at the same time which can save time. So we still have that parallel, but now we actually have a function that lets us run these. So there's gulp.parallel, just like with gulp.series. However, the big difference, obviously, is that this will run them in parallel. And it also accepts a set of functions or string based task names. Now we can go further with this because we can mix and match these things and do some really cool things in Gulp 4. And that's where the power gets unleashed. So, let's take a quick first look at that. If you want to mix and match series and parallel and task names, here's a sample task we can create. One called build. Maybe it's to build our entire pipeline. You want to concatenate and minify and bundle and put file revisions and all sorts of fun stuff in there. So we can define a task and then define a series, and in that series, we want to run this first line here. We're running vet and test in parallel, and then when both of those are done, we want to run the second one there, which is going to be parallel again, running wiredep, styles, and templatecache, all at the same time, but optimize will wait until all three of those are done. So we have a series and then inside of that series we have subsets like running in parallel or we could also embed other series too. So it just gives us more flexibility. But we're here to talk about the migration story. So let's look at what really changed from Gulp 3 to 4 and then let's go and jump into the code and actually do the refactoring to make it work. First, in Gulp 3, we had this for a task signature. We define the first parameter being the name. The second parameter being an optional list of task names, strings that were the dependencies. And then the third parameter being the callback, what actually does the task do? In Gulp 4 we get down to two parameters. The first is the name again. So that hasn't changed at all. But the second one is a function, and that can be a set of tasks to run in series or parallel like we just saw, or it could be a set of functions as well. So if you're thinking ahead to the refactoring that we're about to do, we're just going to take that array of strings from Gulp 3, and we're going to turn that into a function where we can use series and parallel. But how do we get the prerelease of Gulp 4? During pre-release, we can run npm install with --save-dev and then point right to the GitHub repo to the Gulp 4 branch. And that'll install locally for us. But we also need the CLI and we need to install that globally. So we can do npm install -g, point to the repo for the CLI and the branch for that. Now, it's currently in alpha at the time of recording this course, and when it's released we're just going to have to be able to run npm install -g with gulp-cli. And then we can run npm install with --save-dev, just gulp. So now that we know how to migrate, let's go take a look at our code and refactor it to work in Gulp 4.
So first let's kick start things by doing an npm install of the Gulp CLI globally. And that gives us the Gulp CLI. Now let's modify that to get us a local copy of Gulp. We'll do npm install and this time --save-dev in our project. This'll pull down the local version of Gulp 4, which is currently alpha. And to verify what we have, we can type in gulp -v. We can see the CLI version and then the local version. Now let's re-factor our code. The first thing we'll do is comment out the Gulp tasks that do the task listing, because the task engine changed, and there's now a CLI where you can just type in gulp --tasks or task-simple and you can see a list of those tasks. So we don't need that any more. But now let's get to the brass tacks and take a look at the Gulp task called vet. Now this guy actually doesn't have to change. Because remember the API for the new Gulp task is gulp.task. And then we give it a name like this, and then a function. Well, that's exactly the signature we have here on line 14 so we're good to go with a simple task like that. And now the styles, we have to change this one because that erase in text no longer exists. So let's keep that there for a moment and right on top of it, we're going to say go to gulp styles. And now instead of having clean styles there, we're going to say gulp and then we can pick series or parallel. Well, in this case, series makes sense because we want to run the task called clean-styles and then run function, and this is an anonymous function, to go out and do this task here. Now one of the to do's we're going to have is we're going to have to go put the clean-styles task above this. So that's the second part of the re-factor. So let's go get him. So this task down here, and in fact, all of these clean tasks, should be moving up top because people depend upon those. Let's grab all those, and we'll move them up to the top. Now notice, none of those have any dependencies, so those are all good as well. Now we do have a little problem, here. Notice that we put in the gulp.series. That means we're also going to need an additional parenthesis at the end. So now we've got clean-styles which is good to go and we can get rid of that code. And now you can see the similar pattern we're going to do here. We're going to pop in a gulp.series, first run clean-fonts and then run our function to copy the fonts. And then we'll repeat this process for all of the simple tasks that we have. Now when we get down to the task for inject, we have more than one thing going on. So let's take a moment to look at this. Inject is going to depend upon and run wiredep, styles, and templatecache. Now in Gulp 4, what does that really mean? It means that we were running before in parallel, wiredep, styles and templatecache. So what we want to do is run those in parallel, however, we don't want to run the function in parallel as well. This function over here, because you wanted that to wait till those were done. So this is where we can start mixing and matching a little bit. So we're going to say in gulp.series, first run these parallel tasks, and then run this function and we'll just indent just to make it super clear what's happening. And that's going to wrap this guy up. So this series is going to be first on inject, run wiredep, styles and templatecache, all in parallel, when they're all done, then run the function to go ahead and finish this guy. So that's how we can mix and match a little bit. And we'll come down and do a similar thing to the build task. And build, we want to run both those guys. Actually all three, optimize images and fonts, and parallel. So we'll just copy that code right there, where we've got series and then parallel. Then we'll run this anonymous function. And there we go for our task. Now we've got a missing semicolon, so let's fix him. And we'll come back down. Now we get back to simpler ones where we have a gulp.series again. And this again, we'll first run a gulp.series. And that first part of the series is going to be a parallel, which we'll run an inject and test. Then we'll run the function. And that's a longer function. So I'll make sure we get it there. I'll make it a little bit smaller, just so I can see the end of that guy. So he's ending there. We want to make sure we've got the function guy. We get the series, and then the end of the task. I'll make it bigger again. And we'll take Bump, and he's good to go. And we have serve build. So we want to run build first and then we want to run the function to go serve it. And we can repeat that for him. Make sure you get rid of the erase syntax. Now this again, we'll run first, a series. The first part of that is going to be a parallel, which is going to say, run vet and templatecache at the same time, and then run the function. And then we have a similar thing for gulp vet and templatecache which is going to run as part of autotest. Now the next thing we need to do is make sure that anybody depending upon another task has that task to find already, so autotest is pointing to vet and templatecache, they should be up top. I'm pretty sure somebody's going to be depending upon test, so let's copy him out of here. And let's start looking. And I'll bet you, you'll see test being used by somebody. Yep, right there, in parallel, on line 171. So let's move him all the way up to the top here. So he's moved up. Now he depends upon templatecache. Let's go find him. And there's that task. We'll move him up as well. And the good news, if we run this, we're going to see the rest of those errors. So just to see that in action, let's go ahead and flip over to Terminal and let's just run gulp, and then we'll do vet as the default, and it's going to tell us we have some problems. It's noticing that there's no optimize task so, first thing I would do is come up here, and we run and look for optimize. The build task, the first thing it finds, is looking for optimize, so we've got to move optimize above that. So let's go find that guy. So we're going to take optimize, and we'll move him up the chain. And I think I'll just put him right before build, because that's the guy that's using him. And then he's also using images and fonts. Let's make sure nobody's below that. We also need that serve specs is using build specs, so we'll put him below there. And let's go back and run it again and see what other errors we get. This time we had no errors so we might have the good order.
Running the Refactored Tasks
Now we're running and we see that we're vetting out our js int task. Let's actually open up a file and create a problem with jshint. Let's just get rid of a semicolon. We see it's notified in here. Run over there and we should see the problem show up over in Terminal and we do. So let's go get rid of that problem and let's go back into Terminal and let's type in gulp --tasks-simple. And there's a list of all the tasks that we have. Now let's run gulp clean, clean out our build folder and then let's run gulp serve-dev. And this should launch right inside the browser, which it does. And then we can go ahead and make changes on this, too. So let's come over here. We'll put it side-by-side real quick. And let's open up our less file and let's make a change real quick to this guy. I'll make him yellow. And it should inject it over on the right-side hand. And it, well it did, but I didn't type yellow correctly. And now I do, and it puts it in correct. And let's go ahead and put in red. And there we go. And we'll just revert back to what we needed. So we can see our injections working with browser sync. We can also change one of our files, like let's go to dashboard controller. And let's go ahead and just pop in a line. It refreshed everything for me, which is great. And then I can close the browser. So let's run some of our tests. Let's do gulp test. And we can see it right here in Terminal. And all these should do just great. And when that's done, we'll run gulp server-specs. So this should launch the browser again with our Spec Runner. And let's change our title from dashboard to foo. And we should be able to see now that we've got a test that is failing, right there. Should have a title of dashboard. Now let's change that back. Reruns it automatically. And we're all good. Now the one last really big one is to make sure our build pipeline is working. So let's test that out. And there is one mistake we have in there, but let's find it by accident first. So let's go ahead and run gulp build. And this should create inside of our code base and we'll watch it over here. This build folder and fill this guy up, so showing again the Terminal because it's going to take a moment to put it all in there. It's going to run through all of our tests and everything else. And then it's going to pop them into the build folder. So if we pop over here we can see all of our files. And our file revisions and our index HTML and everything looks good. But it's not actually going to serve the code and let's take a look at why first. So if we go over here we look for serve build. Notice here that serve build is going to run build first. And then it's going to run this function. Well, for function to actually run, which is what's actually going to serve it, the build needs a tell function that it's done. And I'll give you a hint. It's not actually telling it that. So over here, let's run this and I'll show you the problem. If we run serve-build, it's going to build everything up again, it's going to run our tests, it's going to do all of our injection. And then it's going to launch it inside of the browser. Supposedly, at least that's the intended action that we want. But what's really going to happen is it's just going to stop. It created the build but it didn't do anything. Now the problem again is because this build task doesn't actually tell serve-build when it's ready. So the series doesn't really complete. So it never goes on to step two. So let's go take a look at the build task, which should be right above it. And notice here we've got this series. It's got our optimize and images and fonts which run other things. But then this function here doesn't actually tell it when it's done. There's no stream in there and there's no done. So we can stick a done on line 167, and we can call it at 178. And we can go back. We'll run our gulp serve-build. This time it should run through the same steps that it did before. And then when it's done, it'll do its injection and it'll notify that it had to go and run the server. And it should crank open the browser and show us our optimized code. So let's take a look at what it did. Notice it launched the browser this time. I'll refresh so we can see the results. There's our optimized code and our scripts. One last thing that's really cool that I'd like to show is if you ever want to see more about your tasks, yes, you can type in tasks-simple and see a whole list of your tasks. But you can also type in just tasks. It'll show you the task tree, which shows you how things are actually being run. So let's take stock in what we just did. In just a matter of minutes, we re-factored our entire Gulp file from 3 to 4 pretty easily.
Installing the Latest Gulp
Now, if you want to go back to using the Gulp 3 code, you can grab the 3 or the 4 code out of the source folder that comes with the course. But you might also want to put Gulp 3 back on your computer, so one thing we can do here is say, npm uninstall -g, and then gulp -cli. That'll unbuild that, and then also inside the folder where our project is we can do npm uninstall --savedev. And then just gulp. And that gets rid of Gulp out of there. So now if we do a Gulp -v, we should see it doesn't know what Gulp is. You want to put it back on our machines, use the npm install -g gulp. Just go ahead and get version three of Gulp and install it globally. And then we can do npm install --save-dev and then get Gulp locally and that'll put it back in our package JSON. So we just removed Gulp 4 and put Gulp 3 back on here. Now, if we run gulp -v, we should see the local CLI version are the same and they're all 3.8. Now we can go back to running the original Gulp file that we created throughout this course.
John Papa is a Principal Developer Advocate with Microsoft and an alumnus of the Google Developer Expert, Microsoft Regional Director, and MVP programs.
Released29 Jan 2015