有没有可能向Gulp传递一个标志来以不同的方式运行任务?

379

通常在Gulp中,任务的结构如下:

gulp.task('my-task', function() {
    return gulp.src(options.SCSS_SOURCE)
        .pipe(sass({style:'nested'}))
        .pipe(autoprefixer('last 10 version'))
        .pipe(concat('style.css'))
        .pipe(gulp.dest(options.SCSS_DEST));
});

有没有可能向gulp传递一个命令行标志(不是任务),并根据该标志有条件地运行任务?例如

$ gulp my-task -a 1

然后在我的 gulpfile.js 文件中:

gulp.task('my-task', function() {
        if (a == 1) {
            var source = options.SCSS_SOURCE;
        } else {
            var source = options.OTHER_SOURCE;
        }
        return gulp.src(source)
            .pipe(sass({style:'nested'}))
            .pipe(autoprefixer('last 10 version'))
            .pipe(concat('style.css'))
            .pipe(gulp.dest(options.SCSS_DEST));
});

12
由于它在 Node 中运行,您可以使用 process.argv 来访问命令行参数。 - zzzzBov
11个回答

531

Gulp没有提供任何这方面的工具,但您可以使用众多命令行参数解析器之一。我喜欢yargs。应该是:

var argv = require('yargs').argv;

gulp.task('my-task', function() {
    return gulp.src(argv.a == 1 ? options.SCSS_SOURCE : options.OTHER_SOURCE)
        .pipe(sass({style:'nested'}))
        .pipe(autoprefixer('last 10 version'))
        .pipe(concat('style.css'))
        .pipe(gulp.dest(options.SCSS_DEST));
});

你也可以将其与gulp-if组合,以条件地流式传输,在开发与生产构建中非常有用:

var argv = require('yargs').argv,
    gulpif = require('gulp-if'),
    rename = require('gulp-rename'),
    uglify = require('gulp-uglify');

gulp.task('my-js-task', function() {
  gulp.src('src/**/*.js')
    .pipe(concat('out.js'))
    .pipe(gulpif(argv.production, uglify()))
    .pipe(gulpif(argv.production, rename({suffix: '.min'})))
    .pipe(gulp.dest('dist/'));
});

然后使用 gulp my-js-taskgulp my-js-task --production 呼叫它。


45
这应该在官方的gulp github页面中进行提及,这是关键性的东西! - Max
2
这个视频讲解了如何在不使用yargs的情况下实现这一点:https://www.youtube.com/watch?v=gRzCAyNrPV8 - plankguy
9
嗨@plankguy,这个视频非常好。谢谢。它展示了如何手动解析环境变量,没有使用任何库。小小的差别在于,视频是关于“环境变量”的,而上面的例子是关于“命令行参数”的,其中Yargs是另一个工具,它通过抽象变量解析来帮助简化消费过程。 - Caio Cunha
12
如果您使用 npm run gulp,则应该像这样使用它:npm run gulp -- --production - ivkremer
3
这个内容字面上出现在gulp官方Github中提到过。 - fracz
显示剩余2条评论

105

编辑

gulp-util已经弃用,应该避免使用,建议改用minimist代替,因为gulp-util已经使用了它。

所以我在我的gulpfile中更改了一些行来删除gulp-util

var argv = require('minimist')(process.argv.slice(2));

gulp.task('styles', function() {
  return gulp.src(['src/styles/' + (argv.theme || 'main') + '.scss'])
    …
});

原文

在我的项目中,我使用以下标志:

gulp styles --theme literature

Gulp提供了一个对象gulp.env来实现这个功能。在较新的版本中,它已被弃用,因此您必须使用gulp-util来实现。任务看起来像这样:

var util = require('gulp-util');

gulp.task('styles', function() {
  return gulp.src(['src/styles/' + (util.env.theme ? util.env.theme : 'main') + '.scss'])
    .pipe(compass({
        config_file: './config.rb',
        sass   : 'src/styles',
        css    : 'dist/styles',
        style  : 'expanded'

    }))
    .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'ff 17', 'opera 12.1', 'ios 6', 'android 4'))
    .pipe(livereload(server))
    .pipe(gulp.dest('dist/styles'))
    .pipe(notify({ message: 'Styles task complete' }));
});

环境设置在所有子任务中都可用。因此我也可以在监视任务上使用该标志:

gulp watch --theme literature

我的样式任务也起作用了。

再见 Ralf


6
当你运行gulp.env时,你会看到控制台日志消息提醒它即将被废弃。建议你使用自己的解析器,作者推荐yargsminimist。请注意保持翻译后的内容通俗易懂,但不要改变原意。 - Caio Cunha
2
谢谢CaioToOn的提示。我已经更新了我的答案和项目;) - RWAM
4
你可以将 util.env.theme ? util.env.theme : 'main' 简写为 util.env.theme || 'main'。顺便加一分。 - Geeky Guy
9
gulp-util 使用 minimist 库进行命令行参数解析。因此,如果您正在使用 gulp-util,则不需要额外的库来实现这一目的。文档:https://github.com/substack/minimist - Rockallite

58

这是我找到的一个快速食谱:

gulpfile.js

var gulp   = require('gulp');

// npm install gulp yargs gulp-if gulp-uglify
var args   = require('yargs').argv;
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var isProduction = args.env === 'production';

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(isProduction, uglify())) // only minify if production
    .pipe(gulp.dest('dist'));
});

命令行界面(CLI)

gulp scripts --env production

原始参考(不再可用):https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-params-from-cli.md

利用 minimist 的替代方法

来自更新的参考:https://github.com/gulpjs/gulp/blob/master/docs/recipes/pass-arguments-from-cli.md

gulpfile.js

// npm install --save-dev gulp gulp-if gulp-uglify minimist

var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var minimist = require('minimist');

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'production' }
};

var options = minimist(process.argv.slice(2), knownOptions);

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(options.env === 'production', uglify())) // only minify if production
    .pipe(gulp.dest('dist'));
});

命令行界面

gulp scripts --env production

2
那个配方链接似乎已经失效了。这里有另一个使用 minimist 包的链接:pass-arguments-from-cli.md。这很有道理,因为 gulp 本身也使用了 minimist(https://github.com/gulpjs/gulp/blob/master/package.json#L27)。 - yuvilio

40

有一种非常简单的方法可以实现on/off标志而不需要解析参数。 gulpfile.js只是像其他文件一样被执行的文件,因此你可以这样做:

var flags = {
  production: false
};

gulp.task('production', function () {
  flags.production = true;
});

使用类似于gulp-if这样的工具来有条件地执行一步操作。

gulp.task('build', function () {
  gulp.src('*.html')
    .pipe(gulp_if(flags.production, minify_html()))
    .pipe(gulp.dest('build/'));
});

运行 gulp build 会生成一个漂亮的 HTML,而 gulp production build 会将其压缩。


2
好主意,避免了使用yargs。我进一步扩展了它,增加了一个“预生产”任务来设置变量,然后“生产”有一个依赖数组 ['build','pre-production']。这样你就可以直接运行 'gulp production'了。 - Keegan 82
不错!我在设置流之前使用它,如下所示:gulp.task('mytask', function() { if (flags.myflag ) { flaggedtask } else { unflaggedask } }); - henry
我认为这是使用Gulp的方法来完成它。 - gztomas
@Keegan'shairstyle82 我做了类似的事情,但是必须利用 run-sequence 来确保在设置 flags 的属性时没有竞争条件。 - CalMlynarczyk
3
这种方法的缺点在于每次想要改变标志变量时,都需要修改gulpfile.js文件,而不能直接在终端传递参数给gulp命令。 - jbyrd
请注意,gulp production build 默认会并行运行 productionbuild 任务,因此这种技术可能会受到竞态条件的影响,虽然很少见。使用 gulp production build --series 来消除这个风险。 - jfroy

36

如果你有一些严格(有序!)的参数,那么你可以通过检查process.argv来简单地获取它们。

var args = process.argv.slice(2);

if (args[0] === "--env" && args[1] === "production");

执行命令:gulp --env production

然而,我认为这太严格了,不够可靠!所以,我稍微调整了一下...最终得到了这个实用函数:

function getArg(key) {
  var index = process.argv.indexOf(key);
  var next = process.argv[index + 1];
  return (index < 0) ? null : (!next || next[0] === "-") ? true : next;
}

它接收一个参数名并在process.argv中搜索。如果没有找到,则返回null。否则,如果没有下一个参数或下一个参数是命令而不是值(我们用破折号区分),则返回true。(这是因为键存在,但没有值)。如果之前的所有情况都失败了,那么我们得到的就是下一个参数值。 > gulp watch --foo --bar 1337 -boom "Foo isn't equal to bar."
getArg("--foo") // => true
getArg("--bar") // => "1337"
getArg("-boom") // => "Foo isn't equal to bar."
getArg("--404") // => null

好的,暂时就这些... 这里有一个使用 gulp 的简单示例:

var gulp = require("gulp");
var sass = require("gulp-sass");
var rename = require("gulp-rename");

var env = getArg("--env");

gulp.task("styles", function () {
  return gulp.src("./index.scss")
  .pipe(sass({
    style: env === "production" ? "compressed" : "nested"
  }))
  .pipe(rename({
    extname: env === "production" ? ".min.css" : ".css"
  }))
  .pipe(gulp.dest("./build"));
});

运行它:gulp --env production


参数名应以破折号(-)为前缀:if (args[0] === '--env' && args[1] === 'production');,至少在gulp 3.8.11中是这样的。 - piotr_cz
@yckart - 你的代码示例中可能需要添加 require('..') 来获取 getArg。 - jbyrd

7

我建立了一个插件,可以将命令行中的参数注入到任务回调中。

gulp.task('mytask', function (production) {
  console.log(production); // => true
});

// gulp mytask --production

https://github.com/stoeffel/gulp-param

如果有人发现了bug或者有改进意见,欢迎提交PR进行合并。


4

如果您正在使用TypeScript (gulpfile.ts),则可以基于@Caio Cunha的优秀答案https://dev59.com/W2Ag5IYBdhLWcg3w7enx#23038290以及上面的其他评论进行以下操作:

安装

npm install --save-dev yargs

typings install dt~yargs --global --save

.ts文件

将以下内容添加到 .ts 文件中:

import { argv } from 'yargs';

...

  let debug: boolean = argv.debug;

需要在每个.ts文件中单独执行此操作(甚至是导入到gulpfile.ts/js中的工具/任务/项目文件)。

运行

gulp build.dev --debug

或者通过npm将参数传递给gulp:

npm run build.dev -- --debug

2
var isProduction = (process.argv.indexOf("production")>-1);

CLI gulp production 命令将调用我的生产任务,并为任何条件设置标志。


2

Pass arguments from the command line

// npm install --save-dev gulp gulp-if gulp-uglify minimist

var gulp = require('gulp');
var gulpif = require('gulp-if');
var uglify = require('gulp-uglify');

var minimist = require('minimist');

var knownOptions = {
  string: 'env',
  default: { env: process.env.NODE_ENV || 'production' }
};

var options = minimist(process.argv.slice(2), knownOptions);

gulp.task('scripts', function() {
  return gulp.src('**/*.js')
    .pipe(gulpif(options.env === 'production', uglify())) // only minify in production
    .pipe(gulp.dest('dist'));
});

然后使用以下命令运行gulp:

$ gulp scripts --env development

Source


1
我们希望为不同的环境传递不同的配置文件--一个用于生产环境,一个用于开发环境,一个用于测试环境。以下是在 gulp 文件中的代码:
//passing in flag to gulp to set environment
//var env = gutil.env.env;

if (typeof gutil.env.env === 'string') {
  process.env.NODE_ENV = gutil.env.env;
}

这是在app.js文件中的代码:
  if(env === 'testing'){
      var Config = require('./config.testing.js');
      var Api = require('./api/testing.js')(Config.web);
    }
    else if(env === 'dev'){
       Config = require('./config.dev.js');
        Api = require('./api/dev.js').Api;
    }
    else{
       Config = require('./config.production.js');
       Api = require('./api/production.js')(Config.web);
    }

然后运行它 gulp --env=testing


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接