Learn how to create, register and run generators.
- TODO
- What is a generator?
- Creating generators
- Registering generators
- Running generators
- Resolving generators
- Discovering generators
- Default generator
- Generators versus plugins
(TOC generated by verb using markdown-toc)
- document generator args
- explain how the
base
instance works - document
env
Prerequisites
- If you're not familiar with plugins yet, it might be a good idea to review the plugins docs first.
Generators provide a convenient way of "wrapping" code that should be executed on-demand, whilst also namespacing the code being wrapped, so that it can be explicitly targeted via CLI or API using a consistent and intuitive syntax.
You can also think of generators as "containers for tasks". For example, this is how you
Generators are plugins that are registered by name. The only difference between a generator and a plugin is how they are registered.
Example
Given this function:
function plugin(app, base, options) {
}
// use as a plugin
app.use(plugin);
// register as a generator
app.register('my-generator', plugin);
Params
app
: instance ofGenerate
created for the generator. Also available asthis
inside the function.base
: "shared" instance ofGenerate
. Also available asapp.base
(orthis.base
)options
: Generator options. Also available asthis.options
When a generator is registered using the .register
method, it's added to the app.generators
object.
app.register('my-generator', function() {});
console.log(app.generators);
{'my-generator': {...}};
When the generator is registered with the .register
methodThe first difference between
Generators may be registered using either of the following methods:
.register
: if the plugin should not be invoked until it's called by.generate
(stays lazy while it's cached, this is preferred).generator
: if the plugin needs to be invoked immediately when registered
Example
var generate = require('generate');
var app = generate();
function generator(app) {
// do generator stuff
}
// register as a generator
app.register('foo', generator);
// or register as a plugin
app.use(generator);
Should I use .generator
or .register
?
In general, it's recommended that you use the .register
method. In most cases generate is smart enough to figure out when to invoke generator functions.
However, there are always exceptions. If you create custom code and notice that generate can't find the information it needs. Try using the .generator
method to to invoke the function when the generator is registered.
Generators and their tasks can be run by command line or API.
Command line
To run globally or locally installed generator-foo
, or a generator named foo
in generator.js
, run:
$ gen foo
"default" task
If generator-foo
has a default
task it will automatically be executed when the $ gen foo
command is given. If a default
task is not defined, the generator function is simply invoked.
API
var generate = require('generate');
var app = generate();
function fn() {
// do generator stuff
}
// the `.register` method does not invoke the generator
app.register('foo', fn);
// the `.generator` method invokes the generator immediately
app.generator('bar', fn);
// run generators foo and bar in series (both generators will be invoked)
app.generate(['foo', 'bar'], function(err) {
if (err) return console.log(err);
});
Generators can be published to npm and installed globally or locally. But you there is no requirement that generators must be published. You can also create custom generators and register them using the .register or .generator methods.
This provides a great deal of flexibility, but it also means that we need a strategy for finding generators when generate
is run from the command line.
- When both a task and a generator have the same name on the same instance, Generate will always try to run the task first (this is unlikely to happen unless you intend for it to - there are reasons to do this)
Since the .build method only runs tasks, you can use this to your advantage by aliasing sub-generators with tasks.
Don't do this
module.exports = function(app) {
app.register('foo', function(foo) {
foo.task('default', function(cb) {
// do task stuff
cb();
});
});
// `.build` doesn't run generators
app.build('foo', function(err) {
if (err) return console.log(err);
});
};
Do this
module.exports = function(app) {
app.register('foo', function(foo) {
foo.task('default', function(cb) {
// do task stuff
cb();
});
});
// `.build` doesn't run generators
app.generate('foo', function(err) {
if (err) return console.log(err);
});
};
Or this
module.exports = function(app) {
app.register('foo', function(foo) {
foo.task('default', function(cb) {
// do task stuff
cb();
});
});
app.task('foo', function(cb) {
app.generate('foo', cb);
});
// `.build` will run task `foo`, which runs the generator
app.build('foo', function(err) {
if (err) return console.log(err);
});
};
When the command line is used, Generate's CLI resolves generators in the following order:
- default generator: attempts to match given names to generators and tasks registered on the
default
generator - built-in generators: attempts to match given names to Generate's built-in generators
- locally installed generators
- globally installed generators
todo
If a generator is registered with the name default
it will receive special treatment from Generate and Generate's CLI. More specifically, when Generate's CLI looks for generators or tasks to run, it will search for them on the default
generator first.
There is a catch...
Registering the "default" generator
The only way to register a default
generator is by creating an generator.js in the current working directory.
When used by command line, Generate's CLI will then use node's require()
system to get the function exported by generator.js
and use it as the default
generator.
The primary difference between "generators" and "plugins" is how they're registered, but there are a few other minor differences:
Plugin | Generator | |
---|---|---|
Registered with | .use method | .register method or .generator method |
Instance | Loaded onto "current" Generate instance |
A new Generate() instance is created for every generator registered |
Invoked | Immediately | .register deferred (lazy), .generator immediately |
Run using | .run: all plugins are run at once | .generate : only specified plugin(s) are run |