web-dev-qa-db-ja.com

Gulp:ウォッチ宣言からタスクにパラメーターを渡す

問題:ファイルの「コレクション」を保持したい。これは、ビルド時間と柔軟性に役立ちます。たとえば、app.jsファイルを編集するたびに、すべてのTwitter bootstrapファイルを再コンパイルしたくありません。

私は確かに2つのタスクと2つのウォッチ宣言でこれを達成できます-問題は、タスクがファイル配列を除いて同一であることです。理想的には、これらをウォッチ宣言のパラメーターとして渡したいのですが、次の擬似コードのようなことをする方法はありますか?

var files = {
    scripts: [
        'www/assets/scripts/plugins/**/*.js', 
        'www/assets/scripts/main.js', 
    ],
    vendor: [
        'vendor/jquery/dist/jquery.js',
        'vendor/jqueryui/ui/jquery.ui.widget.js',                       
        'vendor/holderjs/holder.js'
    ],              
};
...


gulp.task('js', ['lint'], function (files, output) {
    return gulp.src(files)
        .pipe(debug())
        .pipe(concat(output))
        .pipe(uglify({outSourceMap: true}))
        .pipe(gulp.dest(targetJSDir))       
        .pipe(notify('JS minified'))
        .on('error', gutil.log) 
});

...

gulp.watch('scripts/**/*.js', ['lint', 'js'], files.scripts, 'app.min.js');
gulp.watch('vendor/**/*.js', ['lint', 'js'], files.vendor, 'vendor.min.js');

別の方法でめくる:タスクを呼び出したウォッチ宣言に名前空間を付けることですか?そうすれば、どの時計がタスクをトリガーしたかを確認し、タスク自体の中でそれらを条件付けることができます。

24
Beans

問題は、ファイル配列の保存を除いて、タスクが同じであることです。

私は lazypipe(そのghページを参照) があなたの欲求によく適していると信じています。これは興味深い問題でした。私があなたが尋ねていると思うこと(lazypipeで満足)と、おそらくあなたが考えているか、パイプのパラメーター化を通過した場合に考えてしまうと思うものの両方に答えようと思います問題。

必要なことの1つの側面は、変更されていないファイルに対してjshintを再実行したくないことです。さらに、私たちはそれを乾いた状態に保ち、変更されたファイルに加えて新しいファイルを取得したいと考えています。

これはテストされ、私にとってはうまくいきます:

var gulp = require('gulp');
var $ = require('gulp-load-plugins')();
var es = require('event-stream');
var lazypipe = require('lazypipe');
var gutil = require('gulp-util');
var path = require('path');

var files = {
  scripts: ['src/**/*.js'],
  vendor: ['vendor/**/*.js']
};

// sets up a lazy pipe that does jshint related stuff
function getJsMultiPipe(name) {
  return lazypipe()
    .pipe($.jshint)
    .pipe($.jshint.reporter, 'jshint-stylish')

    // if you don't want to fail on style errors remove/comment this out:
    .pipe($.jshint.reporter, 'fail');
}

// sets up a lazy pipe that does concat and post-concat stuff
function getJsCombinedPipe(groupName, outfile) {
  return lazypipe()
      .pipe($.concat, outfile)
      .pipe($.uglify, {outSourceMap: true})
      .pipe(gulp.dest, 'build')
      .pipe($.notify, {message: groupName + ' JS minified', onLast: true});
}

// sets up a pipe for the initial build task, combining the above two pipes
function getBuildPipe(groupName, outfile) {
  return gulp.src(files[groupName])
        .pipe(getJsMultiPipe(groupName)())
        .pipe(getJsCombinedPipe(groupName, outfile)());
}

// sets up a watch pipe, such that only the changed file is jshinted,
// but all files are included in the concat steps
function setWatchPipe(groupName, outfile) {
  return $.watch({
    glob: files[groupName],
    name: groupName,
    emitOnGlob: false,
    emit: 'one'
  }, function(file, done) {
    return file
        .pipe($.debug({title: 'watch -- changed file'}))
        .pipe(getJsMultiPipe(groupName)())
        // switch context
        .pipe(gulp.src(files[groupName]))
        .pipe($.debug({title: 'watch -- entire group'}))
        .pipe(getJsCombinedPipe(groupName, outfile)())
        .pipe($.debug({title: 'watch -- concatted/source-mapped'}))
        .pipe($.notify({message: 'JS minified', onLast: true}));
  });
}

// task to do an initial full build
gulp.task('build', function() {
  return es.merge(
      getBuildPipe('scripts', 'app.min.js'),
      getBuildPipe('vendor', 'vendor.min.js')
  )
  .pipe($.notify({message: 'JS minified', onLast: true}));
});


// task to do an initial full build and then set up watches for
// incremental change
gulp.task('watch', ['build'], function(done) {
  setWatchPipe('scripts', 'app.min.js');
  setWatchPipe('vendor', 'vendor.min.js');
  done();
});

私の依存関係は次のようになります:

  "devDependencies": {
    "jshint-stylish": "^0.1.5",
    "gulp-concat": "^2.2.0",
    "gulp-uglify": "^0.2.1",
    "gulp-debug": "^0.3.0",
    "gulp-notify": "^1.2.5",
    "gulp-jshint": "^1.5.3",
    "gulp": "^3.6.0",
    "gulp-load-plugins": "^0.5.0",
    "lazypipe": "^0.2.1",
    "event-stream": "^3.1.1",
    "gulp-util": "^2.2.14",
    "gulp-watch": "^0.5.3"
  }

[〜#〜] edit [〜#〜]:これをもう一度見ただけで、次の行に気づきました:

    // switch context
    .pipe(gulp.src(files[groupName]))

これを書いてからgulp.src APIが変更されたと私は信じており、現在gulp.srcにパイプしたときにコンテキストが切り替わらないため、この場所で変更が必要になる場合があることに注意してください。新しいバージョンのgulpの場合、何が起こるかは、コンテキストに追加することになると思います。代わりに、おそらく効率が少し失われます。

6
laurelnaiad

私は同じ問題に直面しました-どのようにパラメーターをgulpタスクに渡すかです。この機能が組み込まれていないのは奇妙です(たとえば、パッケージの2つのバージョンをビルドするのは非常に一般的なタスクです。パラメーター化されたタスクは、非常にDRYソリューション)のようです)。

私はそれをできるだけ単純にしたかったので、私の解決策は可能な各パラメーターのタスクを動的に作成することでした。少数の正確に定義された値がある場合は問題なく動作します。 intやfloatなどの広範囲の値に対しては機能しません。

タスク定義は、目的のパラメーターを受け取る関数にラップされ、パラメーターはタスクの名前に追加されます(便宜上、間に「$」を付けます)。

コードは次のようになります。

function construct_js(myname, files, output) {
  gulp.task('js$' + myname, ['lint'], function () {
      return gulp.src(files)
          .pipe(debug())
          .pipe(concat(output))
          .pipe(uglify({outSourceMap: true}))
          .pipe(gulp.dest(targetJSDir))       
          .pipe(notify('JS minified'))
          .on('error', gutil.log) 
  });
}

construct_js("app", files.scripts, 'app.min.js');
construct_js("vendor", files.vendor, 'vendor.min.js');

gulp.watch('scripts/**/*.js', ['lint', 'js$app']);
gulp.watch('vendor/**/*.js', ['lint', 'js$vendor']);

または、データ定義を少し変更して、タスク生成をループで呼び出します(configs配列に新しい「バージョン」を追加すると、すぐに機能します。

var configs       = [
  {
    name : "app",
    output: 'app.min.js',
    files: [                'www/assets/scripts/plugins/**/*.js', 
                            'www/assets/scripts/main.js', 
                        ]
  },
  {
    name : "vendor",
    output: 'vendor.min.js',
    files: [                'vendor/jquery/dist/jquery.js',
                            'vendor/jqueryui/ui/jquery.ui.widget.js',                       
                            'vendor/holderjs/holder.js'
                        ]
  }
];

function construct_js(taskConfig) {
  gulp.task('js$' + taskConfig.name, ['lint'], function () {
      return gulp.src(taskConfig.files)
          .pipe(debug())
          .pipe(concat(taskConfig.output))
          .pipe(uglify({outSourceMap: true}))
          .pipe(gulp.dest(targetJSDir))       
          .pipe(notify('JS minified'))
          .on('error', gutil.log) 
  });
}

for (var i=0; i <  configs.length; i++) {
  construct_js(configs[i]);
}

最後の「for」にアンダースコアを使用すると、次のようになります。

_(configs).each(construct_js);

私は自分のプロジェクトでこのアプローチを使用して、良い結果を得ました。

2
andrew.fox

タスクのラッパー関数を記述してパラメーターをキャプチャし、それをタスクに渡すことができます。例えば。 ( lodash ライブラリを使用して):

// We capture the options in this object. We use gulp.env as a base such that
// options from cli are also passed to the task.
var currentOpts = _.clone(gulp.env);

// Here we define a function that wraps a task such that it can receive
// an options object
function parameterized(taskFunc) {
    return function() {
        taskFunc.call(null, currentOpts);
    }
}

// Here we create a function that can be used by gulp.watch to call
// a parameterized task. It can be passed an object of "task" : {options} pairs
// and it will return a task function that will capture these options
// before invoking the task.
function withArgs(tasks) {
    return function() {
        _.each(tasks, function (opts, task) {
            currentOpts = _.extend(currentOpts, opts);
            gulp.run(task);
            currentOpts = _.clone(gulp.env);
        });
    }
}

var files = {
    scripts : [ "src/**/*.js"],
    vendor : ["vendor/**/*.js"
};

// We pass the task function to parameterized. This will create a wrapper
// function that will pass an options object to the actual task function
gulp.task("js", parameterized(function(opts) {
    gulp.src(files[opts.target])
        .pipe(concat(opts.output));
}));

gulp.task("watch", function() {
    // The withArgs function creates a watch function that invokes 
    // tasks with an options argument
    // In this case it will invoke the js task with the options object
    // { target : "scripts", output : "scripts.min.js" }
    gulp.watch(files.scripts, withArgs({
        js : {
            target : "scripts",
            output : "scripts.min.js"
        }
    }));
    gulp.watch(files.vendor, withArgs({
        js : {
            target : "vendor",
            output : "vendor.min.js"
        }
    }));
});
2
Tiddo