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

Fio*_*ona 30 javascript yeoman yeoman-generator

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

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

我尝试过的:

我认为子生成器是可行的方法,因为我只是在用户请求时创建文件集.但我无法有条件地调用它们并将它们传递给用户提供的输入.我尝试过使用hookFor,但是我得到了断言错误:hookFor must be used within the constructor only.(因为我不希望默认情况下运行它,我正在调用我的子发生器this.prompt(prompts, function (props)).

问题:

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

如果你很友好地回答,请不要认为我尝试了一些明显的东西;-).

Shr*_*ike 32

让我们考虑你有一个generator-blog带有两个子生成器(blog-server和blog-client)的生成器(BlogGenerator):

app\index.js
client\index.js
server\index.js
Run Code Online (Sandbox Code Playgroud)

所以当你运行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}});
  }
};
Run Code Online (Sandbox Code Playgroud)

在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);
  }
}
Run Code Online (Sandbox Code Playgroud)

更新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")
      });
  }
};
Run Code Online (Sandbox Code Playgroud)

我也删除替换yeoman.generators.Baseyeoman.Base.


Tom*_*tes 7

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

docs:http://yeoman.io/authoring/composability.html