我的Yeoman生成器完成安装后如何运行Grunt任务?

时间:2013-09-17 04:24:46

标签: javascript gruntjs yeoman yeoman-generator

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

让我的生成器在安装结束时运行Grunt构建步骤的最佳方法是什么?已经用于调用end的{​​{1}}事件似乎是正确的地方,但我应该如何与Grunt沟通?

3 个答案:

答案 0 :(得分:47)

如果您关注筹码,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' });
};

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

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

来自https://github.com/yeoman/generator/blob/45258c0a48edfb917ecf915e842b091a26d17f3e/lib/actions/install.js#L67-69this.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调用之上添加一些错误处理以确保安全。

答案 1 :(得分:15)

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

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']);
    });

};

答案 2 :(得分:3)

这个问题已经有点陈旧了,但如果有人错过了这个问题,我还是想补充这个问题。现在,安装后流程更容易实现。查看run loop并使用<article v-for="phase in phases" class="phase"> ... Other content ... <div v-for="role in filtered(phase.id) "> <p>${role.title}</p> </div> </article> 方法,您可以在其中运行所有安装后的内容。