Javascript Yeoman:使用用户提供的参数调用子生成器

Javascript Yeoman:使用用户提供的参数调用子生成器,javascript,yeoman,yeoman-generator,Javascript,Yeoman,Yeoman Generator,我正在编写我的第一个Yeoman生成器,它会提示用户输入各种输入,并根据用户的响应有条件地创建文件。我需要能够根据用户输入调用一个子例程(可以是Yeoman子生成器),并将参数传递给它 我希望使用命名函数(不会自动运行)的原因是,有时用户的响应应该调用多个组合函数,有时函数应该单独运行 我尝试过的: 我认为子生成器是最好的选择,因为我只在用户请求时创建文件集。但我很难有条件地调用它们并将用户提供的输入传递给它们。我尝试过使用hookFor,但是我得到了断言错误:hookFor只能在构造函数中使用

我正在编写我的第一个Yeoman生成器,它会提示用户输入各种输入,并根据用户的响应有条件地创建文件。我需要能够根据用户输入调用一个子例程(可以是Yeoman子生成器),并将参数传递给它

我希望使用命名函数(不会自动运行)的原因是,有时用户的响应应该调用多个组合函数,有时函数应该单独运行

我尝试过的:

我认为子生成器是最好的选择,因为我只在用户请求时创建文件集。但我很难有条件地调用它们并将用户提供的输入传递给它们。我尝试过使用
hookFor
,但是我得到了断言错误:
hookFor只能在构造函数中使用。(因为我不希望它在默认情况下运行,所以我从我的
this.prompt(prompts,function(props)
)调用子生成器)

问题:

如何仅在用户请求时(通过提示符)调用例程,并向该例程传递一些用户提供的信息


如果你有足够的回答,请不要假设我已经尝试了一些明显的东西;-)

让我们考虑你有一个生成器<代码>生成器Blog <代码>(Blog生成器),带有两个子生成器(博客服务器和博客客户端):

因此,当您运行
yo blog
时,您需要向用户询问一些选项并运行(可选)子生成器,对吗

要运行子生成器,您需要调用
this.invoke(“生成器名称空间”{options:{}})
。 我们传递的第二个参数可以有
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}});
  }
};
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);
  }
}
在client\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}});
  }
};
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

2015-04更新:yeoman api现在包括
this.composeWith
作为链接生成器的首选方法


文档:

您可以涵盖所有可能的执行场景、条件检查、组合生成器时的提示如果您将生成器解耦并使用“主生成器”,运行上下文循环将帮助您。使用
.composeWith('my-generator',{'options':options})
选项
将配置传递给组合生成器

使用
.composeWith
时,将对所有生成器执行优先级组功能(例如:
提示
写入
…),然后执行下一个优先级组。如果从generatorA内部调用
.composeWith
generatorB,则执行将是,例如:

generatorA.prompting=>generatorB.prompting=>generatorA.writing=> 生成文字

如果您想控制不同生成器之间的执行,我建议您创建一个“主”生成器,将它们组合在一起,如上所述:

//在my generator/generators/turbo/index.js中
module.exports=require('yeoman-generator').Base.extend({
“提示”:函数(){
console.log('prompting-turbo');
},
“写入”:函数(){
console.log('prompting-turbo');
}
});
//在my generator/generators/electric/index.js中
module.exports=require('yeoman-generator').Base.extend({
“提示”:函数(){
log('prompting-zap');
},
“写入”:函数(){
log('writing-zap');
}
});
//在my generator/generators/app/index.js中
module.exports=require('yeoman-generator').Base.extend({
“正在初始化”:函数(){
这个.composeWith('my-generator:turbo');
这个.composeWith('my-generator:electric');
}
});

正是我想要的。谢谢。我知道这是旧的,但离我要找的很近。我的问题是我的子生成器扩展了“yeoman.generators.NamedBase”。当我运行这段代码时,我得到了“错误:没有提供所需的参数名!”我试图找出如何将该名称(即“yo make:controller test”中的“test”)传递给.invoke()调用的子生成器。有什么帮助吗?得到了:this.invoke(“make:controller”,{options:{nested:true,…},args:[this.name]});如果您遇到此错误“未提供必需的参数名yeoman”--以及composeWith。只需将yeoman.generators.NamedBase更改为yeoman.generators.Base