News

Yeoman: A modern workflow for todays designers and developers

The ultimate collection of front-end tools that will make your workflow quicker, smarter and better organised. A new and improved method for building web apps, try it now.

Yeoman

One thing is certain: times sure have changed. Not too long ago, front-end development, though not simple, was manageable. Learn HTML, a bit of CSS, and you’re on your way. These days, however, for lack of better words, there are far more variables to juggle. Preprocessors, performance tuning, testing, image optimisation, and minification represent just a few of the key factors that the modern day front-end developer must keep in mind when working.

For instance, though it’s easy to use, CSS certainly does not scale well. And, while powerful, JavaScript can at times be an ugly and difficult language to work with. Then there’s the performance aspect; no longer are we merely designing for Internet Explorer and Firefox. These days, we have myriad browsers, devices, resolutions, and connection speeds to consider when developing new applications.
To say that ours is an incredibly tough industry would be the understatement of the century.
The upside is that for every road block, solutions have certainly been provided by members of the community. Consider the CSS scaling issue; well, preprocessors, like Sass, LESS, and Stylus were introduced to drastically make our lives easier. What about the nasty CSS3 browser-prefixing issue? Compass takes care of that! And the JavaScript dilemma? Once again, CoffeeScript, and now TypeScript, to the rescue! The only problem is that each new solution requires its own system and process. As one might expect, over time, this can significantly complicate your workflow. Now, we have multiple Terminal tabs open, each monitoring a subset of the files within our projects, listening for changes. And that’s just the tip of the iceberg. We haven’t yet touched on workflow, coding best practices, image optimisation, testing, and developing an automated build process. Even writing about all of these steps is shortening my breath!
Wouldn’t it be fantastic if somebody wrapped up all of these preprocessors and best practices into one easy-to-use package?

SAY HELLO TO YEOMAN

Created by some of the friendly folks at Google (including Paul Irish and Addy Osmani), Yeoman is the solution to your problems. As the core team puts it, Yeoman offers an opinionated workflow to get you up and running with new projects as quickly as possible. But what does this really mean? Well, it offers the ability to scaffold new projects, as well as the necessary frameworks and testing tools. What this essentially translates to is less tedious configuration, and more creation.
To get started with Yeoman, we first need to install it from the command line. Go ahead and run the following command:

001 curl -L get.yeoman.io | bash

This script will perform a variety of things, including installing the necessary libraries for Yeoman to do its job. You’ll likely find that it requires a handful of steps on your part, but, don’t worry; it’ll tell you exactly what needs to be done!
Once the installation completes, run yeoman to see what’s available.
You’ll find a variety of options, such as init for initialising a new project, build for creating a special, optimised dist folder for deployment, and install, which makes the process of dealing with package management as easy as possible.
To learn more about what each of the options actually does, append –help to the command: yeoman init –help.
Let’s create a new project with Yeoman. Create a new directory on your desktop, cd to it from the Terminal, and then run:

001 yeoman init

At this point, the program will prompt you to answer some questions.
• Would you like to include Twitter
Bootstrap for Compass?
• Would you like to include the Twitter
Bootstrap plug-ins?
• Would you like to include RequireJS
(for AMD support)?
• Would you like to support writing ECMAScript 6 modules?

These questions give you the ability to configure your new project right out of the box. For now, choose No to each question.
If you’d prefer to bypass these questions in the future, instead run yeoman init quickstart. This will prepare a new application, with Modernizr, jQuery, and HTML5 Boilerplate baked in.
With that single command alone, Yeoman instantly scaffolds a new project for you. Don’t let yourself be overwhelmed by all of these files, though; if they weren’t generated for you, you’d eventually create them manually.
What do you get with a single yeoman init command? Just think of Yeoman as the helpful robot, who does all of the manual labour for you. ‘Yo, man; go fetch me jQuery and Modernizr!’
Now that we have ourselves a new project, let’s launch a preview server and begin monitoring the application for changes.

001 yeoman server

Instantly, Google Chrome will be launched, displaying your project (also, no more security errors). Well, that’s handy, but as you’ll quickly find, there’s much, much more to see. Place your browser and editor side-by-side, and try the following things:

LIVERELOADING

Change the h1 tag’s text and watch it instantly update in the browser, without a refresh – Yeoman at your service! It achieves this via the LiveReload Google Chrome extension, but, if that’s not installed, a fallback reload process will be used.
SASS
Change main.css to main.sass (or main.scss, if that’s your preference), and enjoy instant compiling and updating in the browser. To test it out, try creating and using a variable.

 001 // main.sass
 002    $textColor: #666
 003 body color: $textColor

Nice! Zero set up required. You are now able to separate your stylesheets, as needed, and import them into main.sass.

 001 // main.sass
 002    @import 'grid'
 003 @import 'buttons'
 004    @import 'module'

Each time a file is saved, Yeoman will automatically re-compile your Sass into regular CSS and refresh the browser for you.

COMPASS

If you’re a Sass fan, then it’s likely that you also prefer the excellent Compass framework. No worries; Yeoman is happy to oblige. Compass support is already available; simply import the applicable modules, and continue as usual.

001 // main.sass
 002    @import 'compass/css'
 003 
 004     *
 005    +box-sizing(border-box)
 006    
 007    .box 
 008 width: 200px
 009    +transition(width 1s)
 010    
 011    &:hover
 012 width: 400px

If you’re not yet a preprocessor convert, you have to admit: this is significantly better than the alternative:

001 * {
 002    -WebKit-box-sizing: border-box;
 003 -moz-box-sizing: border-box;
 004    box-sizing: border-box;
 005    }
 006    007    .box {
 008 width: 200px;
 009    -WebKit-transition: width 1s;
 010    -moz-transition: width 1s;
 011    -ms-transition: width 1s;
 012 -o-transition: width 1s;
 013    transition: width 1s;
 014    }
 015
 016    .box:hover {
 017    width: 400px;
 018    }

COFFEESCRIPT

JavaScript is just fine and dandy, but some feel that CoffeeScript provides a considerably cleaner syntax that fills in many of the gaps in the language.
Within the scripts/ directory, optionally create a new folder, coffee/, and add your first CoffeeScript file: person.coffee.

001    # scripts/coffee/person.coffee    
 002    class Person  

Save the file, and like magic, Yeoman immediately compiles it into vanilla JavaScript, and places the new file directly within the parent scripts/ directory. Why don’t you see for yourself?

001 // scripts/person.js
 002    var Person;
 003 
 004    Person = (function() {
 005    
 006    function Person() {}
 007    
 008 return Person;    })();

Perfect, and more importantly, effortless!
If you need to modify the directory structure in any way, refer to the gruntfile.js file within the root of your application. Behind the scenes, Ben Alman’s Grunt tool is what configures the compilation.
At this point alone, Yeoman has given us a great deal of flexibility. With that single yeoman init command, you may now style your websites with Sass, code in CoffeeScript, and as you make changes, instantly see the updates reflected in the browser. But we’re not done yet, Not even close!

PACKAGE MANAGEMENT

Yeoman leverages a powerful package manager for the web, called Bower. What’s a package manager? Well, if you’re still manually downloading, for instance, the Underscore library from underscorejs.org, then you’re doing it wrong. What happens when the library is updated a few months later? Will you manually redownload the library again? Time is money; so let Yeoman do the work for you.
Let’s pull Underscore into our project.

001 yeoman install underscore

Yeoman will respond to this command by downloading the latest version of the library and placing it within a new vendor directory. Now it’s ready to be used!

001 <script src="scripts/vendor/underscore/    underscore.js"></script>

But, what if we’re not exactly sure what the name of the asset we require is? In these situations, we can refer to Yeoman search. Without passing any arguments, Yeoman will return a list of every asset that is available to install. Let’s search for the popular normalize.css project, by Nicolas Gallagher.
Remember: Bower isn’t exclusively for JavaScript-specific assets.

001 yeoman search normalize

At the time of writing, two projects should be returned to us:

001normalize-css git://github.com/necolas/normalize.css.git
 002underscore.normalize git://github.com/michael-lawrence/underscore.normalize.git

It looks like normalize-css is the one we want.

001 yeoman install normalize-css
Now, import it in the same way that you normally would:

001 <link rel="stylesheet" href="scripts/      vendor/normalize-css/normalize.css">

Alternatively, rename the file to normalize.scss, and import it into your main.sass file.

001 // main.sass   @import '../scripts/vendor/   normalize-css/normalize'

There’s a variety of other Bower-specific commands that you’ll want to remember:
Yeoman uninstall jQuery – Uninstall a package.
Yeoman update jQuery – Update library to the latest version.
Yeoman list – List all currently installed packages.

TESTING

If testing is not yet part of your workflow, it should be! What could be better than a robot that automatically verifies your work after each save?
Luckily, Yeoman makes it incredibly easy to test your applications. Out of the box, the popular Mocha framework and PhantomJS (headless WebKit) are available. However, it’s easily configurable, if you prefer a different tool, like Jasmine. Additionally, it offers the Chai assertion library, which you’ll quickly grow to love.
Open the tests/index.html file. Toward the bottom, you’ll see a couple of sample tests provided. Go ahead and delete those and create a new test file: spec/person.js. Here’s a test to get you started.

001 // test/spec/person.js
 002    describe('A Person', function() {
 003       it('should have an age above 0', function() {
 004               var person = new Person name:    'Jeffrey', age: 27
 005    expect(person.age).to.be.above(0);
 006    
 007          });
 008 });

SHOULD INTERFACE

If you’d prefer to use Chai’s (an assertion library) should interface, return to index.html, and change expect = chai.expect to should = chai.should(). Now, you can update your spec, so that it reads:

001 person.age.should.be.above(0);

Which method you choose is entirely up to you. There is no correct choice; only preferences.
To run this test, return to the Terminal, and type:

001 yeoman test

As expected, the test should fail with the message: “Can’t find variable: Person.” It’s a failing test, but, more importantly, it works – we’re testing! Because Yeoman leverages the excellent PhantomJS tool (headless WebKit), these tests can even be run without the browser.

COFFEESCRIPT TESTS

If you prefer to write your tests in CoffeeScript, you’ll need to make a couple tweaks to your gruntfile.js. Begin by adding a new compile object to the compass task. Within this object, specify the files that should be watched. In this case, we’re instructing Grunt to compile all CoffeeScript files within test/spec/coffee.

001 // Coffee to JS compilation
 002    coffee: {
 003 
 004    dist: {
 005    src: 'app/scripts/**/*.coffee',
 006    dest: 'app/scripts'
 007    },
 008 compile: {
 009      files: {
 010          "test/spec/": "test/spec/coffee/*.    coffee"
 011         }
 012   }
 013    }

The final step is to tell Grunt to keep an eye on that directory. When a file is saved, it should be recompiled, accordingly.
Find the watch task, and update the coffee object, like so:

001 coffee: {
 002       files: ['<config:coffee.dist.src>',      'test/spec/coffee/*.coffee'],
 003 tasks: 'coffee reload'
 004    }

Above, we’re simply adding a new path to the files array. This way, Grunt knows that it needs to watch the test/spec/coffee directory as well for changes, and run the coffee and reload tasks accordingly.

PUTTING IT ALL TOGETHER

To illustrate a few more of Yeoman’s abilities, let’s take this new learning, and apply it to a simple project from scratch. Our goal is to display the latest tweets about Yeoman on the page, and include the tweeter’s avatar, and a link to the original tweet.
We begin by rapidly creating a new application with Yeoman.

001 mkdir tweets && cd tweets   yeoman init     quickstart

Next, we boot up the server and begin watching the Sass and CoffeeScript files for changes. If you’re working along, be sure to place your browser and editor side-by-side for the best workflow.

001 yeoman server

Feel free to remove the boilerplate HTML that Yeoman provides as an example. Next, we’ll start writing the necessary code to fetch the tweets. Within the scripts/ directory, create a new coffee/tweets.coffee file, and reference the compiled version of this file within index.html.
001 <link rel=”stylesheet” href=”scripts/       tweets.js”>

Next, we’ll fetch the desired tweets using Twitter’s easy-to-use Search API. To fetch a JSON file containing these tweets, we can use the following URL: search.twitter.com/search.json?q=yeoman.io. However, because we’ll be fetching this data, using $.getJSON, we’ll need to specify a callback parameter, so that we trigger Twitter’s JSONP format.
Refer to Twitter’s API for more search options. dev.twitter.com/docs/api/1/get/search.
Let’s create the class.

001 # scripts/coffee/tweets.coffee
 002       App = App or {}
 003 
 004        class App.TweetsCollection
 005          constructor: (query = 'yeoman.io',
 006           apiUrl = 'http://search.twitter.com/search.json') ->
 007    
 008     @query = query
 009         @apiUrl = apiUrl
 010    
 011         fetch: ->
 012 
 013         $.getJSON "#{@apiUrl}?q=#{@            query}&callback=?"

Note that we’re using dependency injection (from the constructor) to make the actual process of testing this code (beyond the scope of this tutorial) considerably easier.
If you’d like to try it out, within your browser’s console, just run:

001 var tweets = new App.TweetsCollection      tweets.fetch().done(function(data) {
 002    console.log(data.results);
 003 });

The console should now display a list of tweets, which reference yeoman.io.
Now that we’ve managed to fetch the tweets, we next need to prepare the HTML to display them. While it’s recommended that you use a proper templating engine, such as Handlebars or even Underscore’s implementation, for the purposes of this tutorial we’ll keep it simple. Luckily, CoffeeScript’s block strings and interpolation features make the process of embedding HTML as elegant as possible.

001 class App.TweetsView
 002         el: $('<ul>') 
 003 
 004           constructor: (tweets) ->
 005            @tweets = tweets
 006    
 007           render: ->
 008          $.each @tweets, (index, tweet) =>
 009              # Try to use a templating engine instead.
 010              @el.append """
 011                 <li>
 012                <img
 013    src='#{tweet.profile_image_                 url}'alt='#{tweet.from_user}'>
 014                     #{tweet.text}
 015                         </li> 
 016                    """
 017    @

Note: when you’re ready to use a dedicated templating engine, don’t forget to install it with Yeoman and, behind the scenes, Bower: yeoman install handlebars.
This code is fairly simple. When instantiated, it’ll expect an array of the tweets (which we already know how to fetch). When its render() method is triggered, it will cycle through that array of tweets, and, for each one, append a list item with the necessary data to an unordered list (@el). That’s it!
If you’re curious about the => sign (instead of ->), that’s what we refer to as a fat arrow in CoffeeScript. It ensures that, within the anonymous function, this will still refer to the TweetsView object, instead of just the single tweet.
Now that our code is in place, let’s get the ball rolling! Back to the index.html file, and add a new app.js reference.

001 <script src="scripts/vendor/jquery.min.     js"></script>
 002    <script src="scripts/tweets.js"></script> 
 003 <script src="scripts/app.js"></script>

Within scripts/coffee/app.coffee, add:

001 tweets = new App.TweetsCollection
 002     
 003 tweets.fetch().done (data) ->
 004         tweetsView = new App.TweetsView(data.    results).render()
 005         $(document.body).html tweetsView.el

Upon saving this code, thanks to Yeoman, we can watch the browser instantly refresh to display the latest tweets about Yeoman!
You might be wondering where that done method is coming from. This is necessary because, behind the scenes, when the fetch() method is called on App.TweetsCollection, an AJAX request is being made. As such, a promise is being returned.
Think of a promise as jQuery promising to notify you when an asynchronous operation has completed. When this async request is done, then execute this callback function.
Admittedly, this was a fairly simple project, but Yeoman has significantly improved our workflow.
The final step is to build the project, in order to optimise our assets and images (if applicable) as much as possible.

001 
 002 yeoman build
 003 

This command will instruct Yeoman to run all necessary tasks, and ultimately produce a new dist directory that should be pushed to your server for production. All files will be compressed and optimised. Once the operation completes, we can preview it by running:

001 
 002 yeoman server:dist
 003 

View the source and notice how the assets have been compressed. But we can do better. At this point, the scripts and stylesheets (not applicable in our project) haven’t been concatenated. Let’s fix that with Yeoman! Return to your index.html file, and wrap the script references with an HTML comment, which instructs Yeoman to concatenate and minify the contained files.

001 <!-- build:js scripts/scripts.js -->
 002    <script src="scripts/vendor/jquery.min.     js"></script>
 003 <script src="scripts/tweets.js"></script>
 004    <script src="scripts/app.js"></script>
 005    <!-- endbuild -->

This translates to: when building the project, concatenate all of the files within the build:js comment block, and replace the scripts with a single reference to scripts/scripts.js, which Yeoman will automatically generate for you.
This way, in production, we’re working with only one HTTP request instead of three! This also can be used for your stylesheets, though, if you’re using Sass, it’s unnecessary.
With that change in mind, let’s build and preview the project again.

001 
 002 yeoman build   yeoman server:dist
 003 

It still works! View the source, and notice that we now only have one script reference.

001 
 002 <script src="scripts/110552aa.scripts.      js"></script>
 003 

Folks, this is free optimisation. No hidden fees. Use it! Your final step would be to push the dist folder up to your server, and head home for the day!

CLOSING THOUGHTS

You’ll also be excited to know that there’s still so much more to Yeoman than what has been covered in this article, such as sub-generators. In addition to scaffolding out entire frameworks, we can also rapidly generate the smaller parts, such as for models, views, and so on.
Perhaps the greatest thing about Yeoman is that it’s open. While some similar tools cost money, Yeoman is open source, which means that you – yes you – can fork it, and help improve it!
As the web moves more and more toward client-side-centric applications, Yeoman couldn’t have come at a better time. So, forget the preparation and configuration; let’s start building things.
To stay up to date with the latest Yeoman news, or to make suggestions and log feature requests, feel free to follow @yeoman on Twitter, and subscribe to its Google group (groups.google.com/forum/#!forum/yeoman-dev).

×