Scaffold Three Full-Stack Modern Web Application Examples using Yeoman with npm, Bower, and Grunt
The capabilities of modern web applications have quickly matched and surpassed those of most traditional desktop applications. However, with the increase in capabilities, comes an increase in architectural complexity of web applications. To help deal with the increase in complexity, developers have benefitted from a plethora of popular support libraries, frameworks, API’s, and similar tooling. Examples of these include AngularJS, React.js, Play!, Node.js, Express, npm, Yeoman, Bower, Grunt, and Gulp.
The post’s examples use Yeoman generators. What is a generator? According to Wikipedia, Yeoman’s generator concept was inspired by Ruby on Rails. Using a generator’s blueprint, Yeoman scaffolds an application’s project directory and file structure, and installs required vendor libraries and dependencies. Yeoman generators usually run interactively, guiding the developer through a series of configuration questions. The configuration choices determine the project’s physical structure and components installed by Yeoman.
Generators are inherently opinionated. They dictate a particular application architecture they feel represents current best practices. However, good generators also allow developers to select from a range of architectural choices to meet the requirements of a developer’s environment. For example, a generator might allow Grunt or Gulp for task automation, or allow either Less or Sass for styling the UI. Similar to npm, RubyGems, Bower, Docker Hub, and Puppet Forge, Yeoman provides a searchable public repository. This allows developers to choose from a variety of generators to meet their specific needs.
Preparing the Development Environment
The examples in this post were built on Mac OS X. However, all the tools discussed in the post are available on the three major platforms, Linux, Mac, and Windows. Installation and configuration will vary.
Each of the post’s examples varies, architecturally. However, each also shares several common components, which we will install. They include:
We will use Yeoman, a leading web application scaffolding tool, to quickly build the frameworks for the example applications based on best practices and tooling.
We will use Express, a Node.js web application framework that provides a robust set of features for web applications development, to support our example applications.
We will use MongoDB, a leading open-source NoSQL document database, for all three examples. For two of the examples, you can easily substitute alternate databases, such as MySQL, when configuring the application with Yeoman. The choice of database is of secondary importance in this post.
First install Node.js, which comes packaged with npm. Then, use npm to install Bower, Yeoman, and Grunt. Make sure you run the command to fix the permissions for npm. If permissions are set correctly, you should not have to use
sudo with your npm commands.
The global mode option (
-g) installs packages globally. Packages are usually installed globally, only if they are used as a command line tool, such as with Bower, Yeoman, and Grunt.
The easiest way to install Node.js and npm on OS X, is with Homebrew:
|# install homebrew and confirm|
|ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"|
|# install node and npm with brew and confirm|
|brew install node|
|node --version; npm --version|
Alternatively, install Node and npm by downloading the package installer for Mac OS X (x64) from nodejs.org. If you are not a currently a Homebrew user, I suggest this route. At the time of this post, you have the choice of Node.js version v4.2.3 LTS or v5.1.1 Stable.
Fix the potential permission problem with npm, so
sudo is not required:
|sudo chown -R `whoami` $(npm config get prefix)|
Then, install Yeoman, Bower, and Grunt, globally:
|npm install -g bower yo grunt-cli|
|bower --version; yo --version; grunt --version|
Lastly, install MongoDB. Similar to Node, we can use Homebrew, or download and install MongoDB from the MongoDB website. Review this page for detailed installation and configuration instructions. To install MongoDB with Homebrew, we would issue the following commands:
|brew install mongod|
|sudo mkdir -p /data/db|
|sudo chown -R `whoami` /data/db/|
Example #1: Server-Centric Express Application
To install, download the Express Generator with npm, and install with Yeoman, as follows:
|npm install -g generator-express|
As part of the Express Generator’s configuration process, Yeoman will ask a series of configuration questions. The Express generator offers several choices for scaffolding the application. For this example, we will choose the following options: MVC, Marko, Sass, MongoDB, and Grunt.
Lastly, for a build tool (aka task runner) we will choose Grunt. Grunt and Gulp are the two most popular choices. Either is a proven tool for automation tasks such as minification, compilation, unit-testing, linting, and packaging applications for deployment.
Yeoman uses npm and bower to install the generator’s required packages. Based on our five configuration choices for the Express Generator, npm installed over 225 packages in the project’s local
node_module directory. This includes primary and secondary npm package dependencies. For example, Marko, one of the choices, which npm installed, has 24 dependencies it requires. In turn, each of those packages may have more dependencies. You quickly see why npm, and other similar package managers, are invaluable to building and managing a modern web application. The npm dependencies are declared in the
package.json file, in the project’s root directory.
We will still need to install a few more items. We chose Sass as an Express generator option. Sass requires Ruby, which comes preinstalled on Mac OS X. If you wish, you can upgrade your pre-installed version of Ruby with Homebrew, but it is not required. Sass is installed with RubyGems, a package manager for Ruby. To automate the Sass-related tasks with Grunt, we also need to install the Grunt plug-in for Sass, grunt-contrib-sass, using npm:
|# optional install updated version of Ruby and confirm|
|brew install ruby|
|# install grunt-contrib-sass|
|npm install grunt-contrib-sass --save-dev|
|# install sass and confirm|
|gem install sass|
|gem list sass|
|npm install -g mocha|
Up and Running
Simply running the
grunt command will start the default Generator-Express MVC application. While in development, I prefer to run Grunt with the debug option (
grunt -d) and/or with the verbose option (
grunt -v or
grunt -dv). These options offer enhanced feedback, especially on which tasks are run by Grunt. Review the terminal output to make sure the application started properly.
To confirm the Express application started correctly, in a second terminal window, curl the application using
curl -I localhost:3000. Easier yet, point your web browser to
localhost:3000. You should see the following default web page.
Example #2: Full-Stack MEAN Application
To install theAngularJS Full-Stack Generator, download the with npm and install with Yeoman:
|npm install -g generator-angular-fullstack|
|mkdir demo-web-app-2; cd $_|
|yo angular-fullstack meanapp|
Similar to the Express example, Yeoman will ask a series of configuration questions. We will choose the following options: Jade, Less, ngRoute, Bootstrap, UI Bootstrap, and MongoDB with Mongoose. AngularJS, Express, and Grunt are installed by the generator, automatically. For the sake of brevity, we will not include other available options, including Babel for ES6, OAuth authentication, or socket.io.
After generating the AngularJS Full-Stack project, I received errors regarding PhantomJS. According to several sources, this is not uncommon. The AngularJS Full-Stack project uses PhantomJS as the default browser for Karma, the popular test runner, designed by the AngularJS team. Although npm installed PhantomJS locally, as part of the project, Karma complained about missing the path to the PhantomJS binary. To eliminate the issue, I installed PhantomJS globally with npm. I then manually added the PhantomJS binary path to the
$PATH environment variable:
|npm install -g phantomjs|
|sudo vi ~/.bash_profile|
|# add PHANTOMJS_BIN environment variable (next two lines)|
|# your file/line may vary|
To test Karma, with PhantomJS, run the
grunt test command. This should result in error-free output, similar to the following.
Both the Express and AngularJS examples share several common files and directories. However, one major difference between the two is the client/server oriented directory structure of the AngularJS generator. Unlike the Express example, the AngularJS example has both a client and a server directory. The server-side of the application (aka back-end) is driven primarily by Express and Node. Mongoose serves as an interface between our application’s domain model and MongoDB, on the server-side. Also, on the server-side, Jade is used for HTML templating. The client-side of the application (aka front-end) is driven primarily by AngularJS. Twitter’s Bootstrap and Bootstrap UI offer a responsive web interface for our example application.
Up and Running
grunt serve command will eventually start the default AngularJS Full-Stack application, after running a series of pre-defined Grunt tasks.
Review the terminal output to make sure the application started properly. You may see some warnings, suggesting the installation of several dependencies globally. You may also see warnings about dependency versions being outdated. Outdated versions are one of the challenges with generators that are not constantly kept refreshed and tested with the latest package dependencies. Warnings shouldn’t prevent the application from starting, only Errors.
To confirm the application started, in a second terminal window, curl the application using
curl -I localhost:9000. Easier yet, point your web browser at
localhost:9000. The default web page for the AngularJS Full-Stack web application is much more elaborate than the previous Express example. This is thanks to the Bootstrap and AngularJS client-side components.
Additional Generator Features
The AngularJS Full-Stack generator is capable of generating more than just the default application project. The AngularJS Full-Stack generator contains a set of generators. Beyond generating the basic application framework, you may use the generator to create boilerplate code for AngularJS and Node.js components for endpoints, services, routes, models, controllers, directives, and filters. The generators also provide the ability to prepare your application for deployment to OpenStack and Heroku.
The best place to review available options for the generators is on the GitHub sites. You can display a high-level list of the generator’s features using the
yo --help command. Below are the three generators used in this post.
Below, is an example of generating additional application components using the AngularJS Full-Stack generator. First scaffold a server-side Express RESTful API endpoint, called ‘user’. The single command generates a server-side directory structure and several boilerplate files, including an Express model, controller, and router, and Mocha tests.
Next, generate a client-side AngularJS service, which connects to the server-side, Express RESTful ‘user’ endpoint above. The command creates a boilerplate AngularJS service and Mocha test. Lastly, create an AngularJS route. This generator command creates a boilerplate AngularJS route and controller, Mocha test, Jade view template, and less file.
Example #3: Java Hipster Application
Again, we will use a Yeoman generator, JHipster, built by Julien Dubois and team, to scaffold the application (v2.25.0). According to the project’s GitHub site, JHipster uses a robust server-side Java EE stack with Spring Boot and Maven. JHipster’s mobile-first front-end is enabled with AngularJS and Bootstrap. Being the most complex of the three examples, it’s important to review the project documentation.
JHipster offers three ways to install the application, which are 1) locally, 2) a Docker container, or 3) a Vagrant VM. We will install the application framework locally as not to introduce additional complexity. To install the generator, download the JHipster generator with npm, and install with Yeoman:
|npm install -g generator-jhipster|
|mkdir demo-web-app-3; cd $_|
Again, Yeoman will ask a series of configuration questions on behalf of JHipster. For this example, we will choose the following options: token-based authentication, MongoDB, Maven, Grunt, LibSass (Sass), and Gatling for testing. AngularJS and Bootstrap are installed automatically. We have chosen not to include other configuration options in this example, such as Angular Translate, WebSockets, and clustered HTTP sessions.
Once Yeoman finishes scaffolding the application, you should see the following output.
Maven Project Structure
/src/main/webapp/ directory. The presence of the
node_modules directory, in the project’s root directory.
Up and Running
mvn command will start the default JHipster application. The URL for the JHipster application is included in the terminal output.
To confirm the application has started, curl the application in a second terminal window, using
curl -I localhost:8080. Easier yet, point your web browser to
localhost:8080. Again, thanks to Bootstrap and AngularJS, the application presents a rich client UI.
- Post: Best Web Frameworks (link)
- Post: State Of Web Development 2014 (link)
- YouTube: Modern Front-end Engineering (link)
- YouTube: WebStorm – Things You Probably Didn’t Know (link)
- Website: MEAN Stack (link)
- Website: Full Stack Python (link)
- Post: Best Full Stack Web Framework (link)