
An overview of Yeoman
The term modern webapps is a relatively new thing, as the Web is still in its infancy stage. As the Web matures, so does the need for developer tools and workflows, thanks to some modern-day Web pioneers over at Google. Paul Irish and Addy Osmani have developed a modern workflow that goes by the name of Yeoman.
The Yeoman workflow is a collection of three tools to improve developers' productivity when building web applications: Yo is the scaffolding tool, Grunt is the build tool, and Bower is the package tool.
- Yo is used to scaffold things such as projects and files from templates
- Grunt is used for task management, testing, code linting, and optimization
- Bower is used for package management and to manage client-side dependencies
Yeoman's architecture
The Yeoman toolset runs in the Node.js environment and is invoked from the command line. Each tool is installed using Node's package manager (npm) and uses the npm repository to manage all plugins.
Node's package manager
Node.js is a platform that is built on Chrome's JavaScript runtime engine. Node.js uses an event-driven, non-blocking I/O model that makes it lightweight, efficient, and perfect for real-time applications that run across distributed devices.
The official package manager for Node.js is npm. From Node versions 0.6.3 and up, npm is bundled and installed automatically with the environment. The npm package manager runs through the command line and manages the application dependencies that are available on the npm
registry.
Note
The current Node.js version used in this book is v0.10.28.
Features of Yeoman
Before we dig deep into using each tool of the workflow, let's take a look at some of the Yeoman tooling features that will help you in your next project:
- Quick install: Easily installs all three tools from the npm repository using one command
- Scaffolding: Fast and easy-to-use command-line tool to create new projects or files from templates that individual generators provide
- Build process: Tasks for concatenation, minification, optimization, and testing
- Preview server: Connect LiveReload server to preview your application in the browser
- Package management: Search, install, and manage project dependencies via the command line
- Code linting: Scripts are run against JSHint to ensure language best practices
- Automation: A simple watch task to compile CoffeeScript, LESS, or SASS, and reload the browser upon changes
- Testing: Executes JavaScript code in multiple real browsers with the Karma runner
- Optimization: Images are optimized using OptiPNG and JPEGtran, and HTML is optimized using the HTML minifier
The preceding features are dependent on what the individual generators provide via Grunt tasks. By default, the Angular, Backbone, Ember, and other webapp generators provide tasks to perform all the features listed.
Note
Grunt tasks are individual plugins that perform specific operations on files or folders.
Quick installation
Modern tools usually mean more tools to learn, but learning the tools of the Yeoman workflow is easier than you think. To demonstrate by example, here is how easy it is to get a modern web application up and running, all from the command line.
Installing Yeoman and friends
To install all three tools in the Yeoman workflow, just execute the following command in the terminal:
$ npm install -g yo
The command will install Yo, Grunt, and Bower into your systems path as follows:
- The
-g
option flag specifies the installation to be globally available in your path, allowing theyo
command to be invoked from anywhere - If using the latest versions of Node and Git, Yeoman will automatically install Bower and Grunt while installing Yo
Note
The -g
flag installs globally and requires an administrator user.
If you run into any errors during the initial installation process, you can install the envcheck
module to ensure that your system is ready for all of Yeoman's features; just execute the following command:
$ npm install -g envcheck
Installing a generator
To install generators for Yo, use npm
. Let's install the generic webapp generator; open a terminal and execute the following command:
$ npm install -g generator-webapp
The preceding command will install the webapp generator globally on your system, easily letting you create new web projects within any directory of your choice.
Scaffolding with Yo
Yeoman includes a powerful command-line utility that can scaffold files based on individual generator templates, allowing you to save time creating files from scratch. There are over 700 community generators on npm.
- To search for generators, add the
generator-
prefix before the name, as follows:$ npm search generator-[name]
- To install generators, use
npm install
passing in the name of the package, as follows:$ npm install generator-[name]
Note
The npm
attribute is the package manager for Node.js and comes bundled with it.
Creating the project
All Yeoman commands work off the current directory, so create a new folder named learning-ye
oman-ch1
, open the terminal, and cd
to that location into the newly created directory.
Invoking the generator
Yo, the scaffold tool, will easily create and set up project configuration, files, and folders needed for a modern web application. Execute the following command:
$ yo webapp
Generators can be invoked with different options; in the preceding command, we use the generators' default options that include Mocha as the test framework and JavaScript as the scripting language. You will get an output similar to the following screenshot:

The preceding command does many things. First off, it's going to ask you a few questions about your new project, such as whether to include Twitter Bootstrap with or without Compass SASS and whether to include Modernizr.
Select the first option (Bootstrap), and press Enter; you will see the output to the terminal, and Yeoman is performing all the magic right before your eyes.
Directory structure
Do not be overwhelmed by the number of files generated; take a minute and examine the directory structure that Yeoman produces. You will notice how organized the directory structure is. It looks as follows:
├── Gruntfile.js ├── app │ ├── 404.html │ ├── bower_components │ │ ├── bootstrap │ │ └── jquery │ ├── favicon.ico │ ├── images │ ├── index.html │ ├── robots.txt │ ├── scripts │ │ └── main.js │ └── styles │ └── main.css ├── bower.json ├── node_modules ├── package.json └── test ├── bower.json ├── bower_components ├── index.html └── spec
Just think of Yeoman as a helpful robot that does all the hard work for you, creating all the necessary files and folders to get started with development.
The build process
Yeoman includes Grunt, a task-based command-line tool for JavaScript projects. It is used to perform various build tasks on projects and exposes several useful tasks that you will want to use in your workflow. Yeoman automatically creates and configures Gruntfile.js
, which specifies the configuration of the tasks and targets.
The following order of commands is used for a seamless development workflow:
$ yo webapp #scaffold application $ bower install jquery #install dependency $ grunt serve #start preview server $ grunt test #run unit tests $ grunt #create optimized build
Generally, a modern web developer's workflow consists of the following steps:
- First, scaffold a new application using
yo
. - Search and install third-party client-side libraries using
bower
. - Start a preview server for development that allows you to write code, save it, and watch the results automatically become refreshed.
- Then run the
test
task that executes the tests located in thetest
directory. - Then use the default
grunt
task to run the tests before creating an optimized build.
To view all the installed grunt
tasks associated with the project, you can use the grunt –h
command, which will output a list of all tasks and their descriptions.
The Connect LiveReload server
Now that you have all the initial files and folders for the project, you can really start to see the power of Yeoman.
Previewing the server
Connect LiveReload is the module that is a server that will auto reload when files are changed by the watch process.
To preview the application, execute the following command:
$ grunt serve
The serve task does a few things, which are as follows:
- First, it removes all the files in the
.tmp
directory via the clean task. - It starts the Connect LiveReload server located at 127.0.0.1:9000, and opens the default web browser via the connect task.
- Then, finally, it runs the watch task that monitors the project's source (
app/*
) files, thus executing subtasks on changes.
Your default browser should have opened up, displaying the following page:

Package management with Bower
Yeoman includes an excellent tool called Bower, which is a package manager for the Web and allows you to easily manage dependencies for your projects. Packages can include any type of assets such as JavaScript, images, and CSS. Twitter and the open source community actively maintain it.
Here are some of the available Bower commands:
search
: This command will search for a dependency in the Bower registryinstall
: This command installs one or more dependencieslist
: This command lists all the dependencies installed in the projectupdate
: This command updates a dependency to the latest version
Let's go ahead and add a templating library to our webapp to handle the compilation of model data with HTML for the view. Open the terminal and execute the following command:
$ bower install handlebars --save
This command will download the Handlebars templating library and place the package in the app/bower_components
directory.
To view all client-side dependencies associated with the project, just use the bower list
command that will output a tree of all the installed components and their versions, and also inform us if updates are available, as shown in the following screenshot:

The preceding screenshot is the result of running the bower list
command from within the project's root directory or the directory containing the bower.json
file, which stores all the installed libraries.
The --save
flag tells Bower to write the library name and version to the bower.json
file located in the project's root directory. The bower.json
file is how Bower manages the project's dependencies.
To wire up the newly downloaded package to the application's index.html
page, execute the following grunt
task:
$ grunt bowerInstall
This command will read the contents of the index.html
file in the app
folder. Then, look for the <!-- bower:js -->
block and inject a script tag with the location of the component's main file for each package in the bower_components
directory.
Code linting with JSHint
Yeoman includes JSHint, which is a linting tool that helps developers detect errors and potential problems in their JavaScript code; it is a great way to force best practices and improve the code quality. This is very useful when working with a large code base or in a team environment.
The jshint
task is responsible for linting all code before it gets executed. The following screenshot shows an example of using the jshint
task. It displays the errors that output when code fails the linking process:

Note
For more information on configuring JSHint, visit http://goo.gl/c2lsk1.
Let's begin to add some logic to the applications' main script file that was created during the initial scaffold. Open app/scripts/main.js
and add the following:
/* global Handlebars */ (function () { 'use strict'; window.App = { init: function (config) { console.log( '1 - initialize' ); this.config = config; if (this.config.feature && this.config.feature.endpoint) { this.fetch(); } return this; }, render: function () { console.log( '4 - render' ); var template = Handlebars.compile( $( this.config.el ).find( 'script[type="text/x-handlebars-template"]' ).html() ); var html = template( this.config ); $( this.config.el ).html( html ); return this; }, onSuccess: function (response) { console.log( '3 - onSuccess' ); this.config.features = response; this.render(); }, onError: function (error) { return this.log( error ); }, fetch: function () { console.log( '2 - fetch' ); var self = this; $.ajax( { url: self.config.feature.endpoint, dataType: 'jsonp', success: function (results) { return self.onSuccess( results ); }, error: function (error) { return self.onError( error ); } } ); } }; })(); console.log( 'Allo, Allo!' );
Tip
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
Here is the breakdown of the preceding code:
- First, we define Handlebars' global library to let JSHint know what we are doing.
- Then, we create a new
App
object on the JavaScript globalwindow
object. - The
render
method takes theconfig.el
property and renders the compiled template into the element. - The
init
function takes aconfig
object as the argument and will be set on the class as theconfig
property. - If the passed object has a
feature.endpoint
property, then the app will fetchfeatures
from that endpoint. - The
render
method will compile the Handlebars template with theconfig
object to create the HTML output, which is injected intoconfig.el
. - The
onSuccess
method will set themodel.features
property to theresults
of the request and invoke therender
method to display the contents. - The
onError
method will log the error to the console. - The
fetch
method will invoke a JSONP request toconfig.feature.endpoint
.
Save the file, and the lint task will then compile into JavaScript and reload the browser; nothing will look different because we haven't added the application's template.
Automation
Yeoman comes with a watch
task that is responsible for the automation of different tasks when developing web applications, such as compiling CoffeeScript to JavaScript when source files change or concatenating and parsing SASS files and then reloading the web browser to see changes.
The automation tasks are limited to the Grunt tasks that are defined by the generator; any changes to the .js
or .html
file in the app
directory will automatically get parsed, and the browser will get refreshed. If the watch
task detects changes to files in the test
directory, then the unit tests are run via the test
task.
Let's create the application's template; we will use the {{ }}
double mustache syntax to render the dynamic content. Open the app/index.html
file, and add the following contents inside the body
element right below the browsehappy
code line:
... <![endif]--> <div class="container"> <script type="text/x-handlebars-template"> <div class="header"> <ul class="nav nav-pills pull-right"> <li class="active"> <a href="/">Home</a> </li> {{#each menu}} <li> <a href="#{{route}}">{{name}}</a> </li> {{/each}} </ul> <h3 class="text-muted">{{sitetitle}}</h3> </div> <div class="jumbotron"> <h1>{{feature.title}}</h1> <img src="{{feature.image}}"/> <p class="lead">{{feature.body}}</p> </div> <div class="marketing"> {{#each features}} <div class="media"> <a class="pull-left"> <img src="{{ image }}" class="img-thumbnail"/> </a> <div class="media-body"> <h4 class="media-heading">{{ title }}</h4> <p>{{ body }}</p> </div> </div> {{/ each }} </div> <div class="footer"> <p>{{sitecopy}}</p> </div> </script> </div> <!-- build:js scripts/vendor.js -->
The preceding code is very similar to the HTML that was created by Yeoman, except we are replacing the static content with data for Handlebars to compile the template with dynamic configuration data. Now, let's initialize the application by adding the following script block at the bottom of the app/index.html
file in the app
folder that was created during the initial scaffold:
<!-- build:js({app,.tmp}) scripts/main.js --> <script src="scripts/main.js"></script> <!-- endbuild --> <script> $(document).ready(function() { App.init({ el: '.container', sitetitle : 'Learning Yeoman', sitecopy : '2014 Copyright', version: '0.0.1', feature : { title : 'Chapter 1', body : 'a starting point for a modern web app.', image : 'http://goo.gl/kZZ6dX', endpoint : 'http://jonniespratley.me:8181/api/v2/learning-yeoman-ch1/posts' }, features : null, menu: [ {name: 'About', route: '/about'}, {name: 'Contact', route: '/contact'} ] }); }); </script>
In the preceding code, we perform the following steps:
- First, we use jQuery's
ready
method to wait for the document to finish loading before executing the contents. - Then, a new instance of the
App
class is created, passing in the site configuration options. - The
endpoint
property is set to a simple API endpoint used to access thefeatures
data. - The
el
property is set to thediv.container
element in theindex.html
page. - Then, general site information such as the title, version, and copyright is declared.
- The site feature information is populated with default content, and the site navigation menu array is defined with two items that represent pages.
- Save the file, and you will see your browser automatically reloading with something similar to the following screenshot:
Testing with PhantomJS
If testing is not a part of your workflow, it should be! Yeoman makes it incredibly easy to test your application by setting up a testing environment with the Mocha framework. Other options include Jasmine, QUnit, and just about any other framework. That helpful robot (Yeoman) just saved hours of development time by creating all the necessary configuration files during the initial project scaffold.
Several testing tasks can be customized to do many useful things like showing test results in JUnit for use in many continuous integration systems such as Jenkins and Bamboo. Perform the following steps:
- Open the
Gruntfile.js
file, locate themocha
task object around line #138, and configure the specific options for this target, as follows:... //#138 - Mocha testing framework configuration options mocha: { all: { options: { run: true, log: true, reporter: 'Spec', files: ['<%= config.app %>/scripts/{,*/}*.js'] } } }, ...
In the preceding code:
- We specify where the source of the scripts are by the
files
property - The
run
andlog
properties, as you may have guessed, log the output and run the tests - The
reporter
property isSpec
, so it will display the message in the console
- We specify where the source of the scripts are by the
- Then, the
files
property sets the location of the test specs. Open the default test the generator created,test/spec/test.js
, and add the following:/*global App, expect, it, describe */ 'use strict'; var testApp = null; var config = { el: '.container', sitetitle: 'Learning Yeoman', sitecopy: '2014 Copyright', version: '0.0.1', feature: { title: 'Chapter 1', body: 'a starting point for a modern web application.', image: 'http://goo.gl/kZZ6dX', endpoint: '/posts' }, features: null }; testApp = App.init( config ); describe( 'Learning Yeoman Chapter 1 Test', function () { describe( 'App.init', function () { it( 'should store config on instance', function (done) { expect( testApp.config.version, 'App.config' ).to.equal( config.version ); done(); } ); } ); } );
In the preceding code:
- First, the JShint configuration at the top defines global variables used in the spec
- The
describe
block contains some local variables that define the application's configuration - The
it
block is testing if the configuration options passed to theApp.init
method are correctly set on theconfig
property of thetestApp
instance
Running tests
To run the tests, use the following command:
$ grunt test
The output in the console should look similar to the following screenshot:

As we can see from the output, the configuration of PhantomJS is already taken care of. It nicely starts the PhantomJS browser; after connecting to the browser, it logs the output to the console as the tests run.
Optimizing for production
The default Grunt task ($ grunt
) takes care of optimizing your entire project by doing the following:
- Compiles and concatenates all style sheets together
- Minifies all referenced third-party libraries into a separate file
- Groups Angular modules into a separate minimized file
- Then, it combines all application scripts into one separate file
- All HTML files and images are processed through their corresponding optimizer
- All processed files have a revision number appended to the filename
- All built files are located in the
dist
directory, making your application ready for deployment - To preview what your application runs like once optimized, execute the following command:
$ grunt serve:dist
- Your webapp is fully optimized with fewer requests; now, it loads much faster in the browser, as shown in the following screenshot:
See for yourself; open Chrome Developer Tools and click on the Network tab.