Gulp for handling AngularJS files

Having many AngularJS modules means having many <script> tags. Once you create more modules, you’ll need to add more <script> tags. Later on, there’ll be too many <script> tags to handle. Dependency files must be put in order. Confusion can happen. This might not always be the case for everyone but it’s possible. It was the case for me at least. Take a look at my original index.ejs file before I used Gulp:


<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org">
<head>
<title><%= title %></title>
</head>
<body>
  <section ng-view></section>

  // Here’s all the JS files!
  <script type="text/javascript" src="/lib/angular/angular.js"></script>
  <script type="text/javascript" src="/lib/angular-route/angular-route.js"></script>
  <script type="text/javascript" src="/lib/angular-resource/angular-resource.js"></script>
  <script type="text/javascript" src="/example/example.client.module.js"></script>
  <script type="text/javascript" src="/example/controllers/example.client.controller.js"></script>
  <script type="text/javascript" src="/example/config/example.client.routes.js"></script>
  <script type="text/javascript" src="/example2/example2.client.module.js"></script>
  <script type="text/javascript" src="/example2/controllers/example2.client.controller.js"></script>
  <script type="text/javascript" src="/example2/config/example2.client.routes.js"></script>
  <script type="text/javascript" src="/example3/example2.client.module.js"></script>
  <script type="text/javascript" src="/example3/controllers/example2.client.controller.js"></script>
  <script type="text/javascript" src="/example3/config/example2.client.routes.js"></script>
  <script type="text/javascript" src="/application.js"></script>
</body>
</html>

Wow, just look at all those <script> tags! I have three modules. Each angular module has their own controllers, services, directives, configs, etc. I have to declare angular.js before any javascript file that depends on it. Then angular-route and angular-resource comes after. At the very end, I have my main angular file application.js. If this looks like a lot of script tags to you, imagine adding three more modules. If we’re talking about a big MEAN app project, usually six modules aren’t enough. So before the project gets bigger, I thought maybe I could reduce the amount of script tags; that maybe there’s a way to put all these files into one and still keep things in order of dependency.

I found browserify.js and require.js. I immediately tried to learn them. But before I dove deeper, I also stumbled upon Gulp. I wondered how a task runner could help me solve this problem.

Well for one, I’m working on a lot of JavaScript lately (whether on client-side or server-side). Besides, I’m currently working on a MEAN project. So I’m sure I’ll end up using a task runner eventually. Then, I wouldn’t have to learn another library.

So how did I do it using Gulp?

I installed Gulp globally

Obvious, right?


npm install gulp -g

I installed gulp in the project folder

If you don’t, gulp somehow doesn’t work


cd myProject
npm install gulp --save-dev

Install gulp-concat


npm install gulp-concat --save-dev

Create a gulpfile.js on the root of the project


var gulp = require('gulp'),
   concat = require('gulp-concat');

gulp.task('combine', function() { 
   return gulp.src([ 
      './public/lib/angular/angular.js', 
      './public/lib/angular-route/angular-route.js',
      './public/lib/angular-resource/angular-resource.js', 
      './public/example/*.js', 
      './public/example/**/*.js', 
      './public/example2/*.js', 
      './public/example2/**/*.js', 
      './public/example3/*.js', 
      './public/example3/**/*.js', 
      './public/application.js']) 
    .pipe(concat('ng-app.js')) 
    .pipe(gulp.dest('./public/dist/')); 
});

gulp.task('default', ['combine']);

Awesome! Inside the combine task I was able to specify the files I want to concatenate. They’re all in an array. Their order (from first to last) determines their order in concatenation, therefore, keeping dependencies in check.

gulp-concat enables me to name the concatenated js file. So I called it ng-app.js and all angular files will be in there. I then specified where I want ng-app.js to go.

So I was able to fix my problem all inside that gulp task.

I run the task like so:


$ gulp

I updated my index.ejs file. I replaced all those <script> tags with just one for ng-app.js.


<!DOCTYPE html>
<html xmlns:ng="http://angularjs.org">
<head>
<title><%= title %></title>
</head>
<body>

  <section ng-view></section>

  // Just one JS file for Angular!
  <script type="text/javascript" src="/dist/ng-app.js"></script>
</body>
</html>

I reloaded my MEAN app and it worked exactly how it worked before I ever used Gulp!

Because of this AngularJS problem, I was able to learn Gulp. It’s my first time actually using a task runner! I guess it was just about time. Gulp is truly helpful. Above all, I feel like I can think while typing out what I want because it’s all coded!

Gulp watch and Livereload with PM2

Since I already have a task runner, I decided to use it for more than just concatenating files. If I change anything on my angular files, I want it to reload the app automatically.

I use PM2 to keep the NodeJS server running. PM2 has the --watch command so when I make changes, I don’t have to restart the project. But even with this feature, I still have to refresh the browser. This is where Gulp watch and Livereload come in.

I use Gulp’s watch method to watch the files for changes. So I made a new task between combine and default. I also added the livereload plugin.


...
livereload = require('gulp-livereload');
...

gulp.task('watch', function() {
   livereload.listen();
   gulp.watch(['./public/**/*.js'],['combine']);
});

...

Inside watch I make livereload start listening. Then gulp watches JavaScript files inside the public folder and any of its subfolders. When a change happens, the combine task is called. However, a live reload won’t happen unless we add it to the pipe! So I add another .pipe right after .pipe(gulp.dest('./public/dist')).


gulp.task('combine', function() { 
   return gulp.src([ 
      './public/lib/angular/angular.js', 
      './public/lib/angular-route/angular-route.js',
      './public/lib/angular-resource/angular-resource.js', 
      './public/example/*.js', 
      './public/example/**/*.js', 
      './public/example2/*.js', 
      './public/example2/**/*.js', 
      './public/example3/*.js', 
      './public/example3/**/*.js', 
      './public/application.js']) 
    .pipe(concat('ng-app.js')) 
    .pipe(gulp.dest('./public/dist/'))
    .pipe(livereload()); // Add right here!!
});

Change the default task


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

So when I type gulp on the terminal, the watch task starts and live reload happens when any changes in the files happen. This setup helps me for future concatenations and live reloads for .scss and .css

For example, I can just watch for any .scss file changes.


gulp.task('watch', function() { 
   livereload.listen(); 
   gulp.watch(['./public/**/*.js'],['combine']);

   // Watching for .scss file changes
   gulp.watch(['./public/sass/**/*.scss'], ['sass']); 
});

Gulp seems to be the only thing I need during development phase, for now, anyways. It’s convenient that I can use Gulp to do the concatenation that other libraries already do.