【问题标题】:Yeoman: Call Sub-Generator With User-Supplied ArgumentsYeoman:使用用户提供的参数调用子生成器
【发布时间】:2014-01-10 08:16:54
【问题描述】:

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

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

我尝试过的:

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

问题:

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

如果你好心回答,请不要以为我已经尝试过一些显而易见的事情 ;-)。

【问题讨论】:

    标签: javascript yeoman yeoman-generator


    【解决方案1】:

    假设您有一个生成器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 日更新
    现在不推荐使用invoke,应将其替换为composeWith。但这并不像想象的那么容易。 invokecomposeWith 之间的主要区别在于,现在您无法控制子生成器。您只能声明使用它们。
    下面是上面的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.Base替换的yeoman.generators.Base

    【讨论】:

    • 正是我想要的。谢谢。
    • 我知道这是旧的,但它接近我正在寻找的东西。我的问题是我的子生成器扩展了“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 github.com/yeoman/generator/issues/521
    【解决方案2】:

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

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

    【讨论】:

      【解决方案3】:

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

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

      generatorA.prompting => generatorB.prompting => generatorA.writing => 生成器B.写作

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-07-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多