When I sat down a few weeks ago to write my first Yeoman generator, I was pretty surprised by the lack of resources available beyond the basic Yeoman documentation. While the API docs were decent, the Getting Started section wasn’t. Most of the learning was done on my own. Hopefully this will help other people have an easier time.

As an FYI, or a #TL;DR You can find the completed Yeoman generator built in this app on my GitHub.


First let’s talk about what it is that we’re building. Yeoman is a tool for quickly generating (or in other words, scaffolding) files important to your project, according to specific generators that we as developers can program. Today, we’ll look at a very simple example, which will be a generator that creates Angular directives as components in their own folder, as their own module, with a .js and .tpl.html file. Simple enough, right?

Getting Started

Yeoman depends on a package.json being specifically configured as a Yeoman generator in order to recognize the package you’re building as a scaffolding tool. It’s actually a very simple configuration. In a fresh directory, run npm init in your command line, and make sure that you start the name of your package with generator-. When all is said and done, you should have a package.json that looks like this:

    "name": "generator-webcake",
    "version": "1.0.0",
    "description": "For science, you monster",
    "files": [
    "dependencies": {
        "yeoman-generator": "^0.20.2"

Yeoman will run the generator without the generator-. So using the package.json listed above, we would run this generator by running the following in the command line:

$ yo webcake

The only dependency we have listed is the yeoman-generator, which is the base class that we’ll extend to create our own generator. Remember to run npm install.

You may be wondering about the files array. Let’s talk about that.

Generator Files and Structure

Yeoman has a specific way of doing things. First and foremost, it has a default path for each generator, which is the /app/ directory. So if we wanted to run a generator that has a default scaffold, e.g. yo webcake, our scaffolding files would have to live in the /app/ folder, or we would have to specifically tell Yeoman that our default scaffolding suite lives in a different directory. Today we’ll just go the simple route and put it all in /app/.

If you wanted to have multiple generators in the same package.json, you can have multiple directories with scaffolding suites of their own. You would target those at runtime by listing their directory name in the command line. So if we had another generator living in a sibling directory /science/, you would target it as:

$ yo webcake:science

When Yeoman runs, it looks for an index.js file in whichever directory is being tageted. So let’s go ahead and create a file at /app/index.js in your project. Because you listed the 'app' string in your package.json, Yeoman knows that at the very least there’s a legit scaffold suite living there.

Generator Runtime

Yeoman runs generators through a series of eight methods defined in the generator class, which we as developers have the ability to extend. The following can be found on the Yeoman docs, but I’m adding my own notes for what I’ve found to be useful here as well:

  1. initializing: a method for setting up basic initialization, such as setting some properties names on your generator based on information passed in by the user
  2. prompting: a method reserved for running questions by the user, the answers to which can be used to further define properties on the generator object
  3. configuring: this method is generally used for the initial configuration steps, as well as auto-generating files that you might find necessary and kind of a given, like .gitignore, and .editorconfig as the docs suggest
  4. default: if no specific method of the base generator class is extended, any functionality added to the generator will fall into the default method. I have yet to find a use for it, since when I write generators they use the other available methods instead
  5. writing: actually writing the files based on data fields stored in the generator; this can be done by either copying hard-coded files, or passing data through EJS templates
  6. conflicts: the docs say ‘Where conflicts are handled (used internally)’. If it’s an internal-method to the generator class I’m not sure why it’s exposed to developers, and I have yet to see it used in any generator that I’ve researched
  7. install: where you would either have Yeoman install dependencies – e.g. Bower – or spawn child processes to install them yourself; and you could take this opportunity to inject dependencies into previously-written files as well
  8. end: the cleanup process – removing any temp files that may have been written, running any build or minification tasks, etc.

All said and done, your index.js should look something like this:

    base = require('yeoman-generator').Base;

module.exports = base.extend({
    initializing: () => {},
    prompting:  () => {},
    configuring:  () => {},
    default:  () => {},
    writing:  () => {},
    conflicts:  () => {},
    install:  () => {},
    end:  () => {}

Note that you don’t need to include any methods in your base.extend() that you’re not going to use. This was more for demonstration purposes than for actual development. In a minute, when we build a generator, you’ll see that we can do a lot with only two methods.

Breaking up methods into modules

Personally I’m against having extremely long files in my project. So instead of defining these methods inline, I prefer to import a module as the method definition:

module.exports = base.extend({
    initializing: require('./my-initializing-module')

This also helps for portability if you start to build multiple generators that might use some of the same functionality.

Templates and File Writing

The code and markup that you intend to generate has to come from somewhere. By default, Yeoman looks for the ./templates/ directory in your current generator. So if you’re working int he /app/ folder, it would be /app/templates/.

A generator will either run in the curent working directory (CWD), or the closest parent folder with a .yo-rc file. Note that once the generator has been run, if no .yo-rc had previously existed, you can configure Yeoman to create one in the CWD. That means that you’ll be able to run your generator from sub-folders once it’s been created, and still achieve intended results. You can also always just create projects that have a .yo-rc at their root, or wherever you think the write path should start.

The file destination path is based on the directory in which the generator is run, according to the rules above. Keep this in mind when you’re creating destination paths for your generated files.

One nice thing to note about the Yeoman file-system module is that it creates directories on the fly, as files are written to them. The Yeoman fs won’t throw errors if directories don’t already exist, as opposed to the built-in Node fs.mkdir, which does. You might have seen this before if you’re used to the mkdirp module.

Writing direct copies

There will be files that you’ll want to write explicitly, such as dot-files or HTML templates that start off with a certain structure. For that, there’s the simple fs.copy() method on the generator class, which directly writes the content of a source file to a destination file.

writing: function() {
    // takes two arguments: sourcePath, destPath
    this.fs.copy('_someTpl', 'components/my-component/my-component.html');

Writing dynamic templates

Yeoman comes packaged with EJS, a templating syntax for JavaScript. If you’ve ever used templating languages like PHP or ERB before, then this will look extremely familar. You can look into the EJS documentation for information on how to use it.

When you’re writing dynamic templates, you pass three (up to four, including options) arguments to the fs.copyTpl() method. The first and second match the two above, while the third passes in a data object as template data. For example, if you stored all of your generator template data in this.tplData, you might pass it in as:

writing: function() {
    // takes three arguments: sourcePath, destPath, dataObj
    this.fs.copyTpl('_someTpl', 'components/my-component/my-component.html', {data: this.tplData});

The corresponding template would use whatever properties were set on the this.tplData object as properties of the data object when processing the template:

<% if (!data.cake) { %> <strong><%= data.warning %></strong> <% } %>

Once the template has finished processing, this might yield:

<strong>The cake is a lie!</strong>

The file-system module

On a final note, before we get into writing our generator, I want to point out that Yeoman uses the mem-fs-editor module to write to the file system. Files are first written in memory, and are then generated based on your configurations only after each of the eight exposed generator methods have successfully run. That means you and your users don’t have to worry about errant files showing up in the file system if they abort the process before the generator has finished working, or if they abort the process.

Writing Our Generator

And now, finally, we’ll get to writing our own example generator. Set up a folder structure as follows:

|-- package.json
|-- app
    |-- index.js
    |-- prompting.js
    |-- writing.js
    |-- templates
        |-- _html.txt
        |-- _js.txt

You might notice that I used the .txt extension on the source files that will serve as templates. The reason for that is that my IDE doesn’t have syntax highlighting for EJS, while it does have syntax hints; this means that whenever I use EJS in a .js or .html file, it ends up throwing some ugly error highlighting on my files as I write them. I’d much rather deal with no highlighting at all. Feel free to change those, as the file extension doesn’t matter.

You can use the example at the top of this post for how you should write your package.json.

With that done, write your index.js as follows:

// simple-gen/app/index.js

    base = require('yeoman-generator').Base;

module.exports = base.extend({
    prompting: require('./prompting'),
    writing: require('./writing')

With that written, we’re done with the index.js file. As far as we’re concerned it will only be responsible for acting as a manifest for the modules we’ll import that will actually handle the scaffolding process.


Next, we’ll set up the prompting module, which will be responsible for asking users questions about their generated files. Add the following to prompting.js:

// simple-gen/app/prompting.js
'use strict';

module.exports = function() {
    let done = this.async(),
        questions = [
            // our questions will go here

    this.prompt(questions, (answers => {
        // we'll process our answers here

You might notice that I’m using this a lot. In the run context of actually being called, this will refer to the generator importing this module as its method. While not necessarily obvious, it would act the same way if instead of importing the prompting module, we defined the prompting method inline.

You might notice that we call an asnyc() method on this. That’s a generator method that essentially promisifies the prompting process, forcing the generator to wait for answer processing to be finished before moving on to the next method. If you’ve read my previous blog posts, you’ll notice I’m a huge fan of native ES2015 Promises in Node. I haven’t yet experimented with using those instead; so I’m just going with what I know works.

The two key parts of this block that we’ll be working with are the questions array, and the arrow-function callback that deals with answers.


In Yeoman, questions take the form of objects, with pre-defined properties determining how the question will behave. While you can find all of the properties listed on the Inquirer.js docs, here are the most common, as far as I’ve found:

  • type: the type of question being asked. It will default to input. Other options are:
    • confirm
    • rawlist
    • list
    • password
  • name: the name of the question, which will be used as the corresponding key in the answers object
  • message: the actual question that will be displayed
  • default: the default value that will be provided should a user not enter anything
  • choices: an array of options (could be the result of a function return instead of a literal array)
  • when: a method, or the boolean result of an evaluated property on the answers object. Note that its function form takes the answers object as an argument, with whatever properties have been added at the time it’s called.

The answers to your questions will continuously build an answers object, which will be accessible to questions as they are asked, and then passed to the prompt() method’s callback function; hence the arrow function near the end of the code block in prompting.js.

First run

Believe it or not, at this point we can start testing our module to make sure we can actually run it. The first step is to link it to the global Node registry on your machine. From the root of your generator, where the package.json lives, run npm link in the command line. You might need to sudo. That will link this package as a globally-installed Node module, so that as you change it, your changes will be available throughout your machine.

Next, add the following question to your questions array:

// simple-gen/app/prompting.js

    name: 'directiveName',
    message: 'What would you like to name your directive?',
    default: 'awesomeDir'

And finally, in the prompt() callback, add this line:


Why this.log instead of console.log? Yeoman has a built-in logger, which makes use of whatever environment its running in. Most of the time, yes, it’s interchangeable with the Node console. But in case you ever run your generator in another environment (I don’t know where…) you might want Yeoman to detect the proper logging mechanism.

Your very first Yeoman prompt is ready to run! In a command line anywhere on your machine, run the following:

$ yo webcake

You should see the question ‘What would you like to name your directive?’ with a default answer of ‘awesomeDir’ provided. Whatever you answered should be logged immediately after you hit enter.


We’ll move on for now to talk about how to use the answers object. In a future post, when I talk more about the prompting method, I’ll discuss different ways to work with questions. (This post is already freakishly long.)

Answers can be stored directly to the instance of the generator class that you’re extending; or in other words, they can be stored as a property on this. Replace this.log() with the following:

this.data = answers;

Nice. You’ve saved the answers object to the generator instance so that it can be accessed in all of the other generator methods. If you want to make sure, you can add this.log(this.data); after, and run the generator again to see the entire data object printed out.

Writing templates

Moving on, let’s create our two templates that we’ll use to build our directive: a JavaScript file, and an HMTL file. Easiest first, let’s do the HTML file.

Static template

Let’s open up the _html.txt file, and put together a super-simple template that we can directly copy over to the user’s file system:

<!-- simple-gen/app/templates/_html.txt -->

    <!-- your markup here -->

Yep, that easy. Since we’re not going to make any assumptions about how the user intends to use the directive, we’ll leave it at that.

Open up writing.js, and add the following to start building it out:

// simple-gen/app/writing.js

module.exports = function() {
        name = this.data.directiveName;
    this.fs.copy(this.templatePath('_html.txt'), this.destinationPath(`./components/${name}/${name}.tpl.html`));

If you run your generator now, you’ll create a directory for your directive, and an HTML template that will contain the contents of your _html.txt file. Nicely done, you’ve scaffolded your first Yeoman-generated file!

Dynamic template

In this step we’ll work in the opposite direction so that you can see how we’ll expose data to the fs.copyTpl() method, which will fill out the _js.txt template with data, a la EJS.

Either before or after the fs.copy() method call in writing.js (it doesn’t matter so long as it’s after the const), add:

    {data: this.data}

That’s a long expression, so it’s worth going over:

  • We’re running a copyTpl call on the Yeoman fs module, which will dynamically create a file based on the data we pass in, and a template that we reference.
  • The first argument is the template being referenced. We call this.templatePath to get the path to the template directory, which in this case it the default /app/templates/ path. The argument passed in is the file path that completes the path to the template we want to reference. You can consider it a concatenation between ./templates/ and _js.txt.
  • Similarly, the second argument states where the destination file will be built, starting with the default path (which is in many cases the user’s project root), and then continuing on to name the file path by passing it as an argument.
  • Finally we determine which data will be exposed by passing it in as an object literal in the third argument. In this case, the data property in our EJS _js.txt template will have all of the properties that this.data has in the generator. If you remember, we built that property at the end of the prompting.js file.

With that written, we’re done with writing.js. And hey look, we’re almost done! You can even run this and you’ll see an empty JavaScript file generated, along with your HTML file.

The last step is to build our dynamic template. There are a lot of ways to write directives. Some people return things inline as an object literal (and I’m one of them), while some prefer a class-like prototyping approach, while even others prefer to create an API-like object that references private functions. All are valid, working Angular, so I’m not stating which is right and which is wrong. The next bit simply follows my approach. Feel free to change it to fit your approach.

// simple-gen/app/templates/_js.txt

'use strict';

angular.module(components.<%= data.directiveName %>, [])
    .directive('<%= data.directiveName %>', function() {
        return {
            restrict: 'E',
            scope: {},
            templateUrl: 'components/<%= data.directiveName %>/<%= data.directiveName %>.tpl.html',
            link: function() {


In this case there’s really not a lot going on, so I’ll only highlight the important parts:

  1. We have a new Angular module using the directiveName property on the data object, which was passed in when we called fs.copyTpl. In this case it would be called component.awesomeDir, or whatever the user named their directive when they answered the prompt.
    • In my way of writing Angular, I like to import modules into modules, so in this case I would bring this module we’ve generated into a parent components module as a dependency, which is why it’s written like a property of components using dot-notation.
  2. A directive is declared on the new module, again using the directiveName that was defined during the prompting method run.
  3. Some basic directive stuff is applied.
  4. The URL of the accompanying template is written. Notice that this matches very closely to what we have in our fs.copy method call in writing.js. While that works in this case, you’ll want to make sure it maps to a direct path from your user’s index.html file, or whatever file runs the single-page app.
  5. More straight-up directive stuff, the link method.

And that’s it! Try running it somewhere on your machine. You should end up with a folder structure that looks like:

[application root]
|-- components
    |-- awesomeDir
        |-- awesomeDir.directive.js
        |-- awesomeDir.tpl.html

You can keep adding to the components/ directory by building more and more directives.


That’s the basics in practice. There is so much more that can be added if you’re interested in formalizing this process. You can look into passing the directive name as an argument to the command line call, which Yeoman comes pre-built to accomodate. You can use lodash or another utility module to format text strings passed by the user appropriately, so that there won’t be any spaces or other characters that might violate your jshint. You could add prompts to allow the user to further customize this generator, such as giving the option for restrict values, or optionally passing an inline template instead of a template URL.

In future posts, I’ll address building a complex generator. But for now, this was a good start. Feel free to contact me with any questions.

Leave a Reply