我正在编写我的第一个Yeoman生成器,它会提示用户输入各种输入并根据响应有条件地创建文件。我需要能够根据用户输入调用子程序(可能是Yeoman子生成器),并将参数传递给它。
我想使用命名函数(不会自动运行)的原因是,有时用户的响应应该调用多个函数组合,有时候该函数应该单独运行。
我尝试了什么:
我认为子生成器是可行的方法,因为我只是在用户请求时才创建文件集。但是我无法有条件地将它们称为 并将它们传递给用户提供的输入。我已尝试使用hookFor
,但我收到断言错误:hookFor must be used within the constructor only
。 (因为我不希望它默认运行,所以我从this.prompt(prompts, function (props)
调用子生成器。)
问题:
如何仅在用户请求例程时(通过提示)调用例程,并将该例程传递给用户提供的一些信息?
如果你很友好地回答,请不要认为我尝试了一些明显的事情; - )。
答案 0 :(得分:32)
让我们考虑你有一个带有两个子生成器(blog-server和blog-client)的生成器generator-blog
(BlogGenerator):
app\index.js
client\index.js
server\index.js
因此,当您运行yo blog
时,您可以向用户询问某些选项并运行(可选)子生成器,对吗?
要运行子生成器,您需要调用this.invoke("generator_namespace", {options: {}})
。
我们传递的第二个参数可以有options
字段 - 它的选项对象将被传递给生成器。
在app \ index.js中:
BlogGenerator.prototype.askFor = function askFor() {
var cb = this.async();
// have Yeoman greet the user.
console.log(this.yeoman);
var prompts = [{
name: 'appName',
message: 'Enter your app name',
default: 'MyBlog'
}, {
type: 'confirm',
name: 'createServer',
message: 'Would you like to create server project?',
default: true
}, {
type: 'confirm',
name: 'createClient',
message: 'Whould you like to create client project?',
default: true
}];
this.prompt(prompts, function (props) {
this.appName = props.appName;
this.createServer = props.createServer;
this.createClient = props.createClient;
cb();
}.bind(this));
}
BlogGenerator.prototype.main = function app() {
if (this.createClient) {
// Here: we'are calling the nested generator (via 'invoke' with options)
this.invoke("blog:client", {options: {nested: true, appName: this.appName}});
}
if (this.createServer) {
this.invoke("blog:server", {options: {nested: true, appName: this.appName}});
}
};
在client \ index.js中:
var BlogGenerator = module.exports = function BlogGenerator(args, options, config) {
var that = this;
yeoman.Base.apply(this, arguments);
// in this.options we have the object passed to 'invoke' in app/index.js:
this.appName = that.options.appName;
this.nested = that.options.nested;
};
BlogGenerator .prototype.askFor = function askFor() {
var cb = this.async();
if (!this.options.nested) {
console.log(this.yeoman);
}
}
更新2015-12-21 :
现在不推荐使用invoke
,应将其替换为composeWith
。但它并不像它可能那么容易。 invoke
和composeWith
之间的主要区别在于,现在您无法控制子生成器。你只能声明使用它们
以下是上面的main
方法应该是这样的:
BlogGenerator.prototype.main = function app() {
if (this.createClient) {
this.composeWith("blog:client", {
options: {
nested: true,
appName: this.appName
}
}, {
local: require.resolve("./../client")
});
}
if (this.createServer) {
this.composeWith("blog:server", {
options: {
nested: true,
appName: this.appName
}
}, {
local: require.resolve("./../server")
});
}
};
我还将yeoman.generators.Base
替换为yeoman.Base
。
答案 1 :(得分:7)
2015-04 update:yeoman api现在包含this.composeWith
作为链接生成器的首选方法。
答案 2 :(得分:2)
如果您将发电机分离并使用“主发电机”,则可以涵盖所有可能的执行方案,条件检查,组合发电机的提示。运行上下文循环将帮助您。使用options
.composeWith('my-genertor', { 'options' : options })
将配置传递给组合生成器。
使用.composeWith
时,将对所有生成器执行优先级组功能(例如:prompting
,writing
...),然后执行下一个优先级组。如果您从 generatorA 内部致电.composeWith
至 generatorB ,则会执行,例如:
generatorA.prompting => generatorB.prompting => generatorA.writing => generatorB.writing
如果你想控制不同发电机之间的执行,我建议你创建一个" main"将它们组合在一起的生成器,就像在http://yeoman.io/authoring/composability.html#order上写的那样:
// In my-generator/generators/turbo/index.js
module.exports = require('yeoman-generator').Base.extend({
'prompting' : function () {
console.log('prompting - turbo');
},
'writing' : function () {
console.log('prompting - turbo');
}
});
// In my-generator/generators/electric/index.js
module.exports = require('yeoman-generator').Base.extend({
'prompting' : function () {
console.log('prompting - zap');
},
'writing' : function () {
console.log('writing - zap');
}
});
// In my-generator/generators/app/index.js
module.exports = require('yeoman-generator').Base.extend({
'initializing' : function () {
this.composeWith('my-generator:turbo');
this.composeWith('my-generator:electric');
}
});