Supercharging Yeoman

I recently have become interested in the new project spearheaded by Paul Irish and Addy Osmani called Yeoman. Essentially a static website generator, it has a large amount of neat built in tools such as Grunt and Bower. For my own needs it was missing two things: layout/partial support and a easy way to include a directory of scripts in your markup.

Layout Support

I enjoy writing HTML just as much as the next cat, but if I have the opportunity to use a preprocessor such as Haml or Jade I will take that opportunity. This will usually result in less typing, cleaner syntax and easier debugging. My biggest suprise when I first saw Yeoman was that there was no templating built in out of the box. For myself I prefer jade, and thankfully I found a grunt plugin to compile jade templates and output html. I ended up forking the plugin to add the ability to compile '.handlebars.jade' files to '.handlebars' files. You need to configure your grunt file as follows(feel free to look at mine for reference):

grunt.loadNpmTasks('grunt-jade');
// compile .jade files using jade
jade: {
  html: {
    src: ['app/jade/*.jade', 'app/jade/**/*.jade',
    'app/jade/!_*.jade', 'app/jade/**/!_*.jade'],
    dest: 'app/',
    options: {
      client: false,
      basePath: 'app/jade',
      pretty: true
    }
  }
}
jade: {
  files: [
    'app/jade/*.jade',
    'app/jade/**/*.jade'
  ],
  tasks: 'jade'
}

Once you have this set up you can write layouts and partials to reduce the amount of boilerplate you have to write.

Link to directory of scripts

The second thing I wanted from yeoman was the ability to specify a directory and have my templates magically populated with script tags to the files in that directory. Something similar to the behavior in the rails pipeline but as a template tag. One of the nice parts of Jade is the ability to write functions in the global scope and then reference them in your jade templates. I ended up writing this small helper function to populate my templates with all the files in a directory. It uses the findit module to walk the directories:

var findit = require('findit')

var template = function(name) {
    return '\n';
};

module.exports = function(targetDir) {
    targetDir = targetDir.indexOf('/') === 0 ? targetDir : '/' +
targetDir;

    global.js_dir = function(scriptsDir) {

        scriptsDir = scriptsDir.indexOf('/') === 0 ? scriptsDir : '/' +
scriptsDir;
        var output = '';
        var baseDir = __dirname + targetDir;
        var files = findit.sync(baseDir + scriptsDir);

        for(var i=0; i 1 && filePath[0].length > 1) {
                output = output + template(filePath[0]);
            }
        }

        return output;
    };
};

Then to reference it in your template you do the following:

!= js_dir('models')
!= js_dir('views')

Proxy setup

This is just a bonus. Recently there was a pull request was closed that added proxy support to Yeoman. This is useful if you are building a frontend application to consume an API from a different domain from which you are developing. I used the request library to relay the requests. Here is how I set up my proxy:

// Far above
var request = require('request');

proxies: {
  '^/api/(.+)': function (req, res, next, match) {
    req.url = 'http://localhost:5000/' + match[1];
    request(req, function(error, response, body) {
      res.writeHead(response.statusCode, response.headers);
      res.write(body);
      res.end();
    });
  }
}
Updated on: November 19, 2012
Tags: hobby