Getting yo to Do What yeoman Did

Yeoman had some big changes with its 1.0 release, namely removing its abstraction of Grunt to let the user interact directly with Grunt's build process. This gives you a lot more freedom and access to Grunt's features, but it also works very differently from the original build process. Converting a pre-1.0 app to 1.0 is therefore a bit of a task, and Yeoman's migration page isn't too comprehensive. Here are a few tricks that I had to use to get my Yeoman app to work with 1.0.



The main idea of what we'll be doing here is editing the new 1.0 default Gruntfile.js to do what your old Yeoman build process did (not editing your current pre-1.0 gruntfile!). So if you haven't already, the first thing you should do is create a new 1.0 project that's as similar in configuration to your old project as possible, and import the generated Gruntfile.js. Try building with the grunt command and you'll probably see some things aren't working like they used to.

Coffee Script

You'll probably notice right off the bat that your compiled coffeescript files aren't ending up in an accessible location. I've even seen this in a happen in a newly created 1.0 app, so it's a common problem. Here is a way to tweak your Grunt setup to get a working build process.

By default, it seems Yeoman 1.0 compiles all coffeescript files to a single .js file, but unfortunately it doesn't update its reference to it. If you just want to compile your coffeescript directly to corresponding .js files and worry about concatenation and updating references later, we can edit the gruntfile's coffee task to do just that.

Your current 1.0 gruntfile probably looks something like this:

Before: gruntfile coffee task

coffee: {
    dist: {
        files: {
            ".tmp/scripts/coffee.js": "<%= yeoman.app %>/scripts/**/*.coffee"
        }
    },
...

Like I said, that previous default gruntfile compiles all coffeescript files to one .js file in the .tmp folder and leaves it there. Let's change it to something like this:

Before: gruntfile coffee task

coffee: {
    dist: {
        files: {
            expand: true,
            src: ['<%= yeoman.app %>/scripts/**/*.coffee'],
            dest: './',
            ext: '.js'
      },
...

This will compile all coffeescript files into corresponding .js files in the same directory (scripts/main.coffee goes to scripts/main.js, for example). Then when Grunt concatenates the scripts and copies everything over to the dist/ folder, your newly created js files will be included. The grunt server command will also work as expected, since the js files are with the rest of your files, in place.

With this configuration, you alse need to make sure that your coffee task comes before your jshint task when you build. Otherwise you won't be linting your compiled coffeescript. Change the order at the bottom of the gruntfile where "build" is registered.

Lastly as a note, if you need to tweak the above configuration at all and are looking for a bit of extra guidance, Grunt just updated their documentation and it's pretty thorough and helpful. Check out the configuring tasks page for what all of the above task config means. Config for most commands is pretty much the same, but if you want to see more about the coffee command in specific then checkout grunt-contrib-coffee on github.

JSHint

The default configuration of Yeoman is now to use a .jshintrc file for all jshint configuration, instead of doing it inline. If you simply copy over your jshint options from your pre-1.0 gruntfile, they will not be used! Instead, put all of these options into a .jshintrc file in your application’s root directory. Then, make sure to include it in your gruntfile like this:

jshint: {
    options: {
        jshintrc: ‘.jshintrc’
    }
}

Recursive Directory Search

Most tasks in the new default gruntfile don’t search directories recursively like the old one did. Don’t forget to update these paths to make sure they’re finding all of your working files. Grunt’s syntax for recursively searching directories is /, so finding all .js files in recursively within the scripts/ directory might look like this:

scripts//*.js

Imagemin

As of this writing, the imagemin task appears very broken. Creating a brand new new yeoman project, adding an image to it, and attempting to compile results in the error “Fatal error: ENOENT, no such file or directory ‘dist/images/myimage.png’“. Needless to say, you will probably also run into this error while migrating your pre-1.0 app as well.

For the time being unfortunately, I recommend simply not using the imagemin task by commenting it out in the “build” task at the bottom of the gruntfile. If what appears to be a bug in Yeoman is fixed at some point, then you can uncomment this and use imagemin again. If I can get it working myself in the mean time I will post an update.

Other Sketchiness

The current 1.0 release is just a beta, and because of that it does have a bit of sketchiness associated with it. These are the main problems I ran into that were immediately solvable, but I’ve seen a few other things on the way that seem to be breaking even for basic simple project cases. Desipite this, Yeoman is a great tool that I’m getting a lot of use out of, so I’ll update this article with any other helpful info I come up with as I continue working with Yeoman.