30

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

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

我试过的:

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

问题:

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

如果您愿意回答,请不要假设我已经尝试了一些明显的东西;-)。

4

3 回答 3

33

假设您有一个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}});
  }
};

在客户端\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
Usinginvoke现在已弃用,应替换为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.Baseyeoman.Base.

于 2013-12-27T10:52:10.473 回答
8

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

文档:http: //yeoman.io/authoring/composability.html

于 2015-04-12T17:02:30.780 回答
2

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

当使用.composeWith优先级组函数(例如:promptingwriting...)时,将对所有生成器执行,然后是下一个优先级组。如果您从 generatorA 内部调用.composeWithgeneratorB 执行将是,例如:

generatorA.prompting => generatorB.prompting => generatorA.writing => generatorB.writing

如果你想控制不同生成器之间的执行,我建议你创建一个将它们组合在一起的“主”生成器,就像写在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');
  }
});
于 2016-03-01T06:54:39.687 回答