MEAN Development Workflow Tools - MEAN Machine - A beginner's practical guide to the JavaScript stack (2015)

MEAN Machine - A beginner's practical guide to the JavaScript stack (2015)

MEAN Development Workflow Tools

Sample MEAN App

We’ll need to create a sample MEAN application to see exactly how we can use Bower and Gulp to help our workflow.

Here is the directory structure. Go ahead and create these files and folders.

1 - public/

2 ----- app/

3 ---------- controllers/

4 --------------- mainCtrl.js

5 ---------- views/

6 --------------- pages/

7 -------------------- home.html

8 --------------- index.html

9 ---------- app.js

10 ---------- app.routes.js

11 ----- assets/

12 ---------- css/

13 --------------- style.less

14 - server.js

This will be a MEAN project so go ahead and run:

1 $ npm init

to create a package.json file. All the defaults will be fine when creating this file.

We will now need Express as a dependency so run:

1 $ npm install express --save

Now we have Express. Let’s go into server.js and start our server to serve up our index.html file.

1 // get our packages

2 var express = require('express');

3 var app = express();

4 var path = require('path');

5 var port = process.env.PORT || 8080;

6

7 // configure public assets folder

8 app.use(express.static(__dirname + '/public'));

9

10 // route to send index.html

11 app.get('/', function(req, res) {

12 res.sendFile(path.join(__dirname + '/public/app/views/index.html'));

13 });

14

15 // start the server

16 app.listen(port);

17 console.log('Magic happens on http://localhost:' + port);

This is a very simple file, and all we need to do is grab our dependencies and serve up our index.html file before we start the server.

Let’s quickly wire up the rest of our pages:

public/app/controllers/mainCtrl.js

1 angular.module('mainCtrl', [])

2

3 .controller('mainController', function() {

4

5 var vm = this;

6

7 vm.message = 'this is my message!';

8

9 });

public/app/views/pages/home.html

1 Home Page!

public/app/views/index.html

1 <!DOCTYPE html>

2 <html lang="en">

3 <head>

4 <meta charset="UTF-8">

5 <title>Workflow!</title>

6

7 <!-- For Angular Routing -->

8 <base href='/'>

9

10 <!-- CSS -->

11 <!-- load bootstrap here -->

12 <!-- we'll load the css file in the gulp section -->

13

14 <!-- JS / LIBS -->

15 <!-- load angular and angular-route here -->

16

17 <!-- APP -->

18 <script src="app/controllers/mainCtrl.js"></script>

19 <script src="app/app.routes.js"></script>

20 <script src="app/app.js"></script>

21 </head>

22 <body class="container" ng-app="myApp" ng-controller="mainController as main">

23

24 <div class="jumbotron text-center">

25 <h1>{{ main.message }}</h1>

26 </div>

27

28 <div ng-view></div>

29

30 </body>

31 </html>

public/app/app.js

1 angular.module('myApp', ['app.routes', 'mainCtrl']);

public/app/app.routes.js

1 angular.module('app.routes', ['ngRoute'])

2

3 .config(function($routeProvider, $locationProvider) {

4

5 $routeProvider

6

7 .when('/', {

8 templateUrl : 'app/views/pages/home.html',

9 controller : 'mainController',

10 controllerAs: 'main'

11 });

12

13 $locationProvider.html5Mode(true);

14 });

public/assets/css/style.less

1 /* VARIABLES

2 ====================== */

3 @blue: #A6D0C7;

4 @purple: #993399;

5 @red: #cc3333;

6

7 /* MAIN

8 ====================== */

9 body {

10 background:@blue;

11 color:@purple;

12 border-top:20px solid @red;

13 padding-top:50px;

14 }

Now we can start our server using:

1 $ nodemon server.js

This app won’t do much since we haven’t grabbed Bootstrap, Angular, or Angular Route. We’ll be using a tool called Bower to pull in those resources now.

Bower

Bower is a package manager specifically used for frontend resources. You can use bower to pull in any CSS/JS libraries like Bootstrap, Angular, jQuery, Animate.css, Moment, and so many more.

Bower works very similar to npm. It is just a package manager after all. Just like npm uses a package.json file to read all of the packages that it needs to go and grab, bower uses a bower.json file.

Installing Bower

We will first need to install bower to use it. Luckily it is an npm package so we can install it by typing the following command:

1 $ npm install -g bower

We are installing bower globally with -g so that we have access to it anywhere on our system.

Let’s create a bower.json file by using the init command bower provides. We’ll just stick to all the defaults. Run the following:

1 $ bower init

Now that we have bower and our bower.json file, we will be able to search for and install packages.

Installing a Package

1 $ bower install <package_name> --save

Just like npm, if we add the --save modifier, this package will be saved to our bower.json file.

Let’s install Bootstrap and see how that works.

1 $ bower install bootstrap

We can now see that a new folder was created called bower_components. By default, bower will place packages here.

Other installation methods: You can also install a package based on its GitHub URL. Just type bower install <github-url>.

Searching for Packages

There are two ways to search for a package. With bower installed, you are able to search from the command line.

1 $ bower search <package_name>

This can be tedious and doesn’t really offer the best interface especially when there are a lot of results (try running bower search angular) to see a giant list.

The easier method of searching for packages is through the Bower website. They offer their list of resources available for searching right from their site.

Search Packages on Bower’s Site

Specifying A Directory

By default Bower will place all resources in the root directory in a folder called bower_components. This isn’t the most ideal place to put our files since we have already decided that all files that are associated with the frontend of our applications will be placed in the public/ folder.

Let’s change the default bower folder to public/assets/libs. This can be done by creating a new file in the root of our project. This file will be called .bowerrc and is a very simple file to create.

Here’s our .bowerrc file to move the bower_components folder.

1 {

2 "directory": "public/assets/libs"

3 }

Now our files will be placed in the folder we just specified and we are able to keep our root directly cleaner.

Using a Package

Let’s install all the package that we’ll need for one of our usual MEAN stack applications. Run the following command:

1 $ bower install bootstrap angular angular-route angular-animate --save

Once we have the package in our project, we just need to link to the right files. By clicking through your new public/assets/libs folder, you will be able to determine exactly which file you want.

1 <head>

2 <meta charset="UTF-8">

3 <title>Workflow!</title>

4

5 <!-- CSS -->

6 <link rel="stylesheet" href="assets/libs/bootstrap/dist/css/bootstrap.min.css">

7

8 <!-- JS / LIBS -->

9 <script src="assets/libs/angular/angular.min.js"></script>

10 <script src="assets/libs/angular-route/angular-route.min.js"></script>

11 <script src="assets/libs/angular-animate/angular-animate.min.js"></script>

12

13 <!-- APP -->

14 <script src="app/controllers/mainCtrl.js"></script>

15 <script src="app/app.routes.js"></script>

16 <script src="app/app.js"></script>

17 </head>

Now we can see our application in our browser after we start our server using:

1 $ nodemon server.js

You can start to see how your workflow becomes much faster. You’ll just need to run two commands (bower init and bower install <package_name> --save) and then you have all the assets you need.

This allows for a much cleaner process than going through and finding the assets online, downloading, linking, and all that mess. Also, like npm, having your dependencies defined in one file lets other developers know exactly what is needed for the current project.

Gulp

You may have heard of the task runner Grunt. Gulp is the newer kid on the block, but it improves on Grunt in a few ways, the most important being a much simpler syntax for configuration.

So what exactly is a task runner? A task runner like Gulp is able to help automate any tasks you may have in your development process. This could include things like:

· linting files (checking them for errors)

· minifying files

· process LESS or SCSS

· concatenating multiple files into one

· Gulp can even start our nodemon server for us

· so much more…

Installing Gulp

Just like Bower and Nodemon, we are going to install gulp globally so that we have access to it across our projects.

1 $ npm install -g gulp

We will also want to install gulp in our specific project’s devDependencies.

1 $ npm install gulp --save-dev

Great! Now we have Gulp ready to go and we can start to use it. First, let’s compile our LESS file we created earlier into a CSS file so our browser will be able to use it.

Compiling LESS

Each task we will want to do is an npm package that extends Gulp. For example, since we want to compile LESS files, we will need to also install gulp-less. Let’s do that now

1 $ npm install gulp-less --save-dev

Now that we have that plugin, let’s go ahead and use it. Like Bower and npm, we will need a configuration file in the root of our document. This file will tell Gulp exactly what to do when we start it up.

First we will need to create a gulpfile.js in the root of our document.

Inside of our gulpfile.js let’s start using LESS:

1 // load the plugins

2 var gulp = require('gulp');

3 var less = require('gulp-less');

4

5 // define a task called css

6 gulp.task('css', function() {

7

8 // grab the less file, process the LESS, save to style.css

9 return gulp.src('public/assets/css/style.less')

10 .pipe(less())

11 .pipe(gulp.dest('public/assets/css'));

12

13 });

Congratulations, you’ve just made your first Gulp task! Now all we have to do is go back into our command line and type:

1 $ gulp css

That tells Gulp to run that specific task and then we can see that our new style.css file will be generated in the gulp.dest() folder that we specified.

LESS Compiled

LESS Compiled

You can see that the LESS is compiled to CSS just as we would expect.

LESS vs. CSS

LESS vs. CSS

Minifying CSS

The great thing about Gulp is that we are able to pipe a file (or multiple files) through more than one package in one task. Let’s see how we can add CSS minifying to this so that we have a style.min.css to use in production.

First install the gulp-minify-css package as well as a package called gulp-rename so that we can rename our file to style.min.css:

1 $ npm install gulp-minify-css gulp-rename --save-dev

Now we can add it to our gulpfile.js and use it in the css task.

1 // load the plugins

2 var gulp = require('gulp');

3 var less = require('gulp-less');

4 var minifyCSS = require('gulp-minify-css');

5 var rename = require('gulp-rename');

6

7 // define a task called css

8 gulp.task('css', function() {

9

10 // grab the less file, process the LESS, save to style.css

11 return gulp.src('public/assets/css/style.less')

12 .pipe(less())

13 .pipe(minifyCSS())

14 .pipe(rename({ suffix: '.min' }))

15 .pipe(gulp.dest('public/assets/css'));

16

17 });

Now when we run

1 $ gulp css

We can see a new style.min.css file created and it is compiled LESS and minified! We can now go into our index.html file and add our new CSS file:

1 <link rel="stylesheet" href="assets/css/style.min.css">

All those colors. Isn’t it pretty?

Site with LESS

Site with LESS

Using a Gulp Package

The process for using a Gulp package is similar to what we just did with LESS.

1. Install the package and --save-dev

2. Load the plugin in your gulpfile.js

3. Configure a task and use the plugin!

Gulp is easier to configure than Grunt, but the concept is the same: install a package, load it, and configure. Let’s move onto other important tasks that deal with JS.

Linting JS

Let’s make sure that our JS files have no errors. This includes our Node and Angular files. We’ll be using a JSHint plugin called gulp-jshint for this task.

Let’s install this new package:

1 $ npm install gulp-jshint --save-dev

Now let’s bring it into our gulpfile.js and create a brand new task called js.

1 ...

2 var jshint = require('gulp-jshint');

3

4 // css task goes here

5

6 // task for linting js files

7 gulp.task('js', function() {

8

9 return gulp.src(['server.js', 'public/app/*.js', 'public/app/**/*.js'])

10 .pipe(jshint())

11 .pipe(jshint.reporter('default'));

12

13 });

The cool thing we are doing here is using multiple files (passed in as an array) to gulp.src(). We are also using the * wildcard to match any files in the public/app/ folder and any files in subfolders of that folder.

Go into server.js and delete a semicolon so that there is something for our jshint to find. Now type:

1 $ gulp js

And we will see the error!

JSHint

JSHint

Minifying, and Concatenating JS

Currently, the <head> of our applications have looked like this:

1 <head>

2 <meta charset="UTF-8">

3 <title>Workflow!</title>

4

5 <!-- For Angular Routing -->

6 <base href='/'>

7

8 <!-- CSS -->

9 <link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.1/css/boo\

10 tstrap.min.css">

11 <link rel="stylesheet" href="assets/css/style.css">

12

13 <!-- JS / LIBS -->

14 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular.min.js"><\

15 /script>

16 <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.8/angular-route.js"\

17 ></script>

18

19 <!-- APP -->

20 <script src="app/controllers/mainCtrl.js"></script>

21 <script src="app/app.routes.js"></script>

22 <script src="app/app.js"></script>

23 </head>

As our applications start to grow, then we’ll have many more requests which will bog down the performance of our application, especially with the custom Angular components we will have like controllers and services.

We will be using two packages to minify and concatenate (bundle together) our JS files so that we will only need to load a single JS file. Our index.html file will look very clean with only one JS file to load!

Let’s install the two packages, gulp-uglify (for minifying) and gulp-concat.

1 $ npm install gulp-uglify gulp-concat --save-dev

Let’s add them to our gulpfile.js and create a new task just for our frontend JS resources since we don’t want our backend Node files loaded on the frontend.

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

2 var uglify = require('gulp-uglify');

3

4 // task to lint, minify, and concat frontend files

5 gulp.task('scripts', function() {

6 return gulp.src(['public/app/*.js', 'public/app/**/*.js'])

7 .pipe(jshint())

8 .pipe(jshint.reporter('default'))

9 .pipe(concat('all.js'))

10 .pipe(uglify())

11 .pipe(gulp.dest('public/dist'));

12 });

This new scripts task will take all of our frontend Angular files, and bundle them all together in a file called public/dist/all.js.

Sure enough, that file shows all of our Angular files (controller, route, and main app file).

All JS

All JS

We can do the same for all of our Angular library files like angular and angular-route as well. Just add them to the gulp.src() array.

Minifying Angular

There is a problem however when we minify Angular files. Angular files have to be declared a certain way or the minifying process will break them.

The Way to Declare Angular Modules for Minification

So far in this book, we have gone with the easier way of defining modules for simplicity. This looks like the following:

1 angular.module('myApp', ['ngRoute'])

2

3 .config(function($routeProvider, $locationProvider) {

4 // stuff here

5 })

6

7 .controller('mainController', function($http) {

8 // stuff here

9 });

The way to declare Angular modules for minification is the following:

1 angular.module('myApp', ['ngRoute'])

2

3 .config([

4 '$routeProvider',

5 '$locationProvider',

6 function($routeProvider, $locationProvider) {

7 // stuff here

8 }

9 ])

10

11 .controller('mainController', ['$routeProvider', function($http) {

12 // stuff here

13 }]);

Feel free to use the above code and declare modules this way from now on, even though that syntax is annoying to write. There is however another way to minify your Angular files that involves Gulp and another Gulp package.

Using Gulp to Prepare Minifying Angular

Gulp has a package for this specific purpose called gulp-ng-annotate.

Let’s go ahead and install the package:

1 $ npm install gulp-ng-annotate --save-dev

Now we can use the package in our gulpfile.js and create a new task:

1 var ngAnnotate = require('gulp-ng-annotate');

2

3 // task to lint, minify, and concat frontend angular files

4 gulp.task('angular', function() {

5 return gulp.src(['public/app/*.js', 'public/app/**/*.js'])

6 .pipe(jshint())

7 .pipe(jshint.reporter('default'))

8 .pipe(ngAnnotate())

9 .pipe(concat('app.js'))

10 .pipe(uglify())

11 .pipe(gulp.dest('public/dist'));

12 });

Now can run:

1 $ gulp angular

And we will see our new app.js created with the right versions of our Angular files.

ng-annotate

ng-annotate

Watching for Changes

Next up, we will automate Gulp so that we don’t have to go into the command line every time we make a file change and type gulp <task_name>.

The task to watch files is built into Gulp so there’s no need to install a package here. It is important to note however that there is a package out there that is used for more complex setups where there are many files to watch; that package is called gulp-watch.

Let’s go into our gulpfile.js and set it to watch specific files. We will also tell Gulp what tasks to run when a file change has been detected.

1 gulp.task('watch', function() {

2 // watch the less file and run the css task

3 gulp.watch('public/assets/css/style.less', ['css']);

4

5 // watch js files and run lint and run js and angular tasks

6 gulp.watch(['server.js', 'public/app/*.js', 'public/app/**/*.js'], ['js', 'ang\

7 ular']);

8 });

We have defined a CSS file to watch, and the task to run (which we created earlier). Now when we update our style.less file, we can see Gulp go ahead and update the new style.min.css.

Gulp Watch

Gulp Watch

Super fast!

Starting a Node Server

We can also use Gulp to start our server. It will just use nodemon but, it’s kind of cool to just start up our entire application by typing one command: gulp.

The package needed here is gulp-nodemon. Let’s install:

1 $ npm install gulp-nodemon --save-dev

To configure this package is a little different then we’re used to. We will have to define a few things like starting file (server.js), types of files to watch (js less html), and the tasks to run.

1 var nodemon = require('gulp-nodemon');

2

3 // the nodemon task

4 gulp.task('nodemon', function() {

5 nodemon({

6 script: 'server.js',

7 ext: 'js less html'

8 })

9 .on('start', ['watch'])

10 .on('change', ['watch'])

11 .on('restart', function() {

12 console.log('Restarted!');

13 });

14 });

15

16 // defining the main gulp task

17 gulp.task('default', ['nodemon']);

Notice how we defined the files to start with and the extensions to watch for. We also defined the tasks (watch in this case) to work on server start and change.

We are also defining a task called default which is the task that Gulp automatically looks for at first.

Now we can run our task with:

1 $ gulp

We can see our server start and Gulp watching for any files. When a file is changed, Gulp will run the right tasks and then restart the server!

Gulp Nodemon

Gulp Nodemon

All of our great development tools are now bundled into this one gulpfile.js and we are more efficient developers! There are many more great Gulp plugins to look through, so have fun experimenting with other plugins like imagemin and clean.