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.