25

我正在构建一个自定义 Yeoman 生成器,它安装了许多预处理语言编译器,如 CoffeeScript、LESS 和 Jade。在我的生成器创建的 Gruntfile 中,我有一个编译所有内容的构建任务。但是,在该构建任务至少运行一次之前,已编译的 HTML、CSS 和 Javascript 文件不存在,如果我在新搭建脚手架后尝试运行 grunt watch/connect 服务器,这可能会令人困惑。

让我的生成器在安装结束时运行 Grunt 构建步骤的最佳方法是什么?end已经被用来调用的事件this.installDependencies似乎是这样做的正确位置,但我应该如何与 Grunt 沟通?

4

3 回答 3

49

如果您遵循堆栈,this.installDependencies最终会向下运行到https://github.com/yeoman/generator/blob/45258c0a48edfb917ecf915e842b091a26d17f3e/lib/actions/install.js#L36

this.spawnCommand(installer, args, cb)
  .on('error', cb)
  .on('exit', this.emit.bind(this, installer + 'Install:end', paths))
  .on('exit', function (err) {
    if (err === 127) {
      this.log.error('Could not find ' + installer + '. Please install with ' +
                          '`npm install -g ' + installer + '`.');
    }
    cb(err);
  }.bind(this));

进一步追究这一点,this.spawnCommand来自https://github.com/yeoman/generator/blob/master/lib/actions/spawn_command.js

var spawn = require('child_process').spawn;
var win32 = process.platform === 'win32';

/**
 * Normalize a command across OS and spawn it.
 *
 * @param {String} command
 * @param {Array} args
 */

module.exports = function spawnCommand(command, args) {
  var winCommand = win32 ? 'cmd' : command;
  var winArgs = win32 ? ['/c'].concat(command, args) : args;

  return spawn(winCommand, winArgs, { stdio: 'inherit' });
};

换句话说,在您的生成器代码中,您可以this.spawnCommand随时调用,并将您希望终端运行的参数传递给它。如中,this.spawnCommand('grunt', ['build'])

那么下一个问题是你把它放在哪里?线性思考,你只能相信grunt build在安装了所有依赖项之后它才会起作用。

https://github.com/yeoman/generator/blob/45258c0a48edfb917ecf915e842b091a26d17f3e/lib/actions/install.js#L67-69接受回调, this.installDependencies因此您的代码可能如下所示:

this.on('end', function () {
  this.installDependencies({
    skipInstall: this.options['skip-install'],
    callback: function () {
      this.spawnCommand('grunt', ['build']);
    }.bind(this) // bind the callback to the parent scope
  });
});

试一试!this.spawnCommand如果一切顺利,您应该在该新调用之上添加一些错误处理以确保安全。

于 2013-09-24T15:02:44.277 回答
16

我使用了斯蒂芬的出色答案,通过自定义事件以下列方式实现以保持整洁。

MyGenerator = module.exports = function MyGenerator(args, options, config) {

    this.on('end', function () {
        this.installDependencies({
            skipInstall: options['skip-install'],
            callback: function() {
                // Emit a new event - dependencies installed
                this.emit('dependenciesInstalled');
            }.bind(this)
        });
    });

    // Now you can bind to the dependencies installed event
    this.on('dependenciesInstalled', function() {
        this.spawnCommand('grunt', ['build']);
    });

};
于 2013-09-25T10:45:44.203 回答
4

这个问题已经有点老了,但是如果有人错过了,我仍然想添加这个。安装后流程现在更容易实施。查看运行循环并使用end可以运行所有安装后内容的方法。

于 2016-08-04T10:04:32.003 回答