Cara menjalankan tugas Gulp secara berurutan satu demi satu

398

dalam cuplikan seperti ini:

gulp.task "coffee", ->
    gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean",->
    gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"

Dalam developtugas saya ingin menjalankan cleandan setelah selesai, jalankan coffeedan ketika sudah selesai, jalankan sesuatu yang lain. Tapi saya tidak bisa mengetahuinya. Bagian ini tidak berfungsi. Mohon saran.

iLemming
sumber
10
Modul run-sequence npm memperbaiki masalah ini sekarang - semua jawaban lain sekarang tidak relevan - lihat jawaban OverZealous di bawah ini
danday74
1
Gulp 4.0 secara asli mendukung menjalankan tugas secara berurutan, menjadikan run-sequenceusang - lihat jawaban massanishi di bawah ini
Forivin
Gulp4 memecah lebih banyak hal daripada memperbaiki, tampaknya. Setelah berjuang dengannya selama beberapa jam, saya kembali ke 3.9.1. Saya menyadari bahwa versi utama dapat / akan memecah backcompat tetapi dengan pesan kesalahan yang samar dan tidak berguna, saya katakan tidak, terima kasih. v4 belum siap.
Sab Thiru

Jawaban:

121

Ini belum rilis resmi, tetapi datangnya Gulp 4.0 memungkinkan Anda melakukan tugas-tugas sinkron dengan gulp.series dengan mudah. Anda bisa melakukannya seperti ini:

gulp.task('develop', gulp.series('clean', 'coffee'))

Saya menemukan posting blog yang bagus memperkenalkan cara meningkatkan dan memanfaatkan fitur-fitur yang rapi: bermigrasi ke tegukan 4 sebagai contoh

massanishi
sumber
3
Metode pilihan untuk semua pendatang baru. Mereka harus benar-benar mulai dengan tegukan 4, melompati semua 3. * kerumitan dan berbagai antipatterns.
metalim
187
ini 2017 dan mereka masih tidak memperkenalkannya. Bagus.
Tomasz Mularczyk
14
Saya tidak mengerti intinya, sungguh. Jika Anda benar-benar membutuhkan A untuk menjalankan hanya setelah B berjalan, maka A tergantung pada B. Mengapa Anda tidak bisa menentukan bahwa B adalah ketergantungan dari A? gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
musicin3d
3
@ musicin3d Apa yang Anda katakan berhasil, tetapi Anda harus menggabungkan satu tugas dengan yang sebelumnya. Sebagai contoh, saya ingin dapat membangun tanpa harus selalu menyisir sebelumnya. Ini adalah solusi yang lebih baik untuk memiliki tugas independen dan memutuskan urutan pelaksanaan dengan alat eksternal.
AxeEffect
11
itu 2018 dan mereka akhirnya memperkenalkannya. Bagus.
dargmuesli
411

Secara default, tegukan menjalankan tugas secara bersamaan, kecuali mereka memiliki dependensi eksplisit. Ini tidak terlalu berguna untuk tugas-tugas seperti clean, di mana Anda tidak ingin bergantung, tetapi Anda membutuhkannya untuk berjalan sebelum yang lainnya.

Saya menulis ini run-sequenceplugin yang khusus untuk memperbaiki masalah ini dengan tegukan. Setelah Anda menginstalnya, gunakan seperti ini:

var runSequence = require('run-sequence');

gulp.task('develop', function(done) {
    runSequence('clean', 'coffee', function() {
        console.log('Run something else');
        done();
    });
});

Anda dapat membaca instruksi lengkap pada paket README - ini juga mendukung menjalankan beberapa rangkaian tugas secara bersamaan.

Harap dicatat, ini akan (secara efektif) diperbaiki dalam rilis besar gulp berikutnya , karena mereka sepenuhnya menghilangkan pemesanan dependensi otomatis, dan menyediakan alat yang mirip denganrun-sequence untuk memungkinkan Anda menentukan secara manual menjalankan pesanan seperti yang Anda inginkan.

Namun, itu adalah perubahan besar yang melanggar, jadi tidak ada alasan untuk menunggu kapan Anda dapat menggunakannya run-sequencehari ini.

Terlalu bersemangat
sumber
2
@Terimakasih terima kasih untuk plugin! Btw, gulp-cleanplugin tidak menerapkan Streams 2, jadi ada masalah yang dijalankan sebagai dependensi. Ini telah diperbaiki pada versi rilis 0.3.0, rekan kerja saya mengirimkan PR untuk mengkonversinya.
knownasilya
3
@Indolering Fungsionalitas ketergantungan tugas bawaan tidak menyelesaikan skenario ini. Tugas dependen selalu dijalankan: tidak ada cara dibangun untuk menjalankan dua tugas berturut-turut beberapa waktu, tetapi tidak setiap waktu. run-sequenceMemecahkan bagian penting dari fungsionalitas yang hilang di tegukan.
OverZealous
2
Juga, dependensi tugas bukan solusi lengkap. Katakanlah saya memiliki dua tugas tegukan yang menjalankan tes menggunakan database secara independen. Tidak ada yang bergantung pada yang lain, tapi saya tidak ingin keduanya berjalan pada saat yang sama karena mereka berdua perlu menggunakan database.
peterjwest
3
Modul menakjubkan - Inilah penjelasan yang bagus tentang mengapa itu diperlukan - blog.mdnbar.com/gulp-for-simple-build-proccess - Ini harus menjadi jawaban yang diterima
danday74
5
Saya bersyukur Anda membuat solusi untuk ini, tetapi tidak masuk akal bahwa kita membutuhkan perangkat tambahan untuk mendapatkan eksekusi berurutan. Eksekusi berurutan harus menjadi default, atau setidaknya mudah dilakukan. Makefiles telah melakukan eksekusi berurutan selama 40 tahun. Ekosistem JS membuat saya mual. 73 megabyte node_modules hanya untuk mengkompilasi proyek boilerplate tanpa fitur apa pun, dan itu masih belum termasuk kemampuan eksekusi berurutan. Sistem operasi cocok di ruang yang lebih kecil dan mereka memiliki kernel dan driver FFS.
joonas.fi
371

Satu-satunya solusi yang baik untuk masalah ini dapat ditemukan dalam dokumentasi tegukan yang dapat ditemukan di sini

var gulp = require('gulp');

// takes in a callback so the engine knows when it'll be done
gulp.task('one', function(cb) {
  // do stuff -- async or otherwise
  cb(err); // if err is not null and not undefined, the orchestration will stop, and 'two' will not run
});

// identifies a dependent task must be complete before this one begins
gulp.task('two', ['one'], function() {
  // task 'one' is done now
});

gulp.task('default', ['one', 'two']);
// alternatively: gulp.task('default', ['two']);
Mathieu Borderé
sumber
6
Untuk beberapa alasan saya ReferenceError: err is not definedmencoba menjalankan ini pada gulp-compasstugas, apakah saya melewatkan sesuatu?
waffl
11
@waffl contoh ini menggunakan panggilan balik, yang bukan satu-satunya cara untuk melakukan ini. Menurut dokumen , Anda juga dapat "mengembalikan janji atau aliran yang harus ditunggu mesin untuk diselesaikan atau diakhiri masing-masing." Jadi, jika Anda mengembalikan aliran dalam tugas satu, misalnya return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');, kuncinya adalah mengidentifikasi tugas satu sebagai dependen ketika mendefinisikan tugas dua: gulp.task('two', ['one'], function() {... Tugas dua sekarang akan menunggu tugas satu untuk berakhir sebelum berjalan.
esvendsen
24
Ini menciptakan hubungan yang erat antara 'satu' dan 'dua'. Bagaimana jika Anda ingin menjalankan 'dua' tanpa menjalankan 'satu'
wilk
5
Anda mendefinisikan tugas baru tanpa ketergantungan?
Mathieu Borderé
8
Membutuhkan dua tugas untuk berjalan berurutan menyiratkan kopling ketat.
Ringo
56

Saya membuat aplikasi simpul / teguk menggunakan generator Yeoman generator -gulp-webapp . Ini menangani "teka-teki bersih" dengan cara ini (menerjemahkan ke tugas asli yang disebutkan dalam pertanyaan):

gulp.task('develop', ['clean'], function () {
  gulp.start('coffee');
});
Steve
sumber
2
Ini tepat (dan sangat sederhana) yang saya butuhkan. Ini membahas skenario di mana saya perlu melakukan sesuatu seperti clean sebagai dependensi sebelumnya untuk membangun dependensi tanpa menetapkan clean sebagai dependensi pada tugas-tugas itu. PS: Info tentang bit gulp.start () - emptorat
Jaans
Itu masuk akal; panggilan balik setelah tugas utama (dan tugas tergantungnya) selesai. Terima kasih.
markau
4
Jika seseorang bertanya-tanya mengapa tidak ada dokumentasi resmi untuk gulp.start()ini, jawaban dari anggota tegukan ini menjelaskan bahwa: gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it(sumber: github.com/gulpjs/gulp/issues/426#issuecomment-41208007 )
thybzi
1
Dalam hal ini, bagaimana saya bisa mendeteksi coffeetugas itu selesai? Jika saya tidak mendeteksinya, developtugas akan selesai lebih awal daricoffee
thybzi
sudah mendapat jawaban dari run-sequencekode sumber:gulp.on('task_stop') . Lihat jawaban saya untuk perincian: stackoverflow.com/a/38818657/3027390
thybzi
32

run-sequence adalah cara yang paling jelas (setidaknya sampai Gulp 4.0 dilepaskan)

Dengan run-sequence , tugas Anda akan terlihat seperti ini:

var sequence = require('run-sequence');
/* ... */
gulp.task('develop', function (done) {
    sequence('clean', 'coffee', done);
});

Tetapi jika Anda (karena alasan tertentu) lebih suka tidak menggunakannya, gulp.startmetode akan membantu :

gulp.task('develop', ['clean'], function (done) {
    gulp.on('task_stop', function (event) {
        if (event.task === 'coffee') {
            done();
        }
    });
    gulp.start('coffee');
});

Catatan: Jika Anda hanya memulai tugas tanpa mendengarkan hasil, developtugas akan selesai lebih awal dari coffee, dan itu mungkin membingungkan.

Anda juga dapat menghapus pendengar acara saat tidak diperlukan

gulp.task('develop', ['clean'], function (done) {
    function onFinish(event) {
        if (event.task === 'coffee') {
            gulp.removeListener('task_stop', onFinish);
            done();
        }
    }
    gulp.on('task_stop', onFinish);
    gulp.start('coffee');
});

Pertimbangkan juga ada task_erracara yang mungkin ingin Anda dengarkan. task_stopdipicu pada penyelesaian yang berhasil, sementara task_errmuncul ketika ada beberapa kesalahan.

Anda juga mungkin bertanya-tanya mengapa tidak ada dokumentasi resmi untuk gulp.start(). Jawaban dari anggota tegukan ini menjelaskan hal-hal berikut:

gulp.start sengaja tidak didokumentasikan karena dapat menyebabkan rumitnya membangun file dan kami tidak ingin orang menggunakannya

(sumber: https://github.com/gulpjs/gulp/issues/426#issuecomment-41208007 )

thybzi
sumber
dua kopi untuk pria ini! solusi dengan menghapus pendengar bekerja dengan sempurna!
daniel.bavrin
Ini benar-benar jawabannya, atau hanya, "teguk 4". Urutan run kuat.
LAdams87
26

Menurut dokumen Gulp:

Apakah tugas Anda berjalan sebelum dependensi selesai? Pastikan tugas dependensi Anda menggunakan petunjuk run async dengan benar: menerima panggilan balik atau mengembalikan janji atau aliran acara.

Untuk menjalankan urutan tugas Anda secara sinkron:

  1. Kembalikan aliran acara (mis. gulp.src) gulp.taskKe untuk memberi tahu tugas saat aliran berakhir.
  2. Menyatakan dependensi tugas dalam argumen kedua gulp.task.

Lihat kode revisi:

gulp.task "coffee", ->
    return gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean", ['coffee'], ->
      return gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"
senornestor
sumber
4
INI harus menjadi jawaban yang benar! Tugas kembali melakukan trik! Terima kasih sobat.
Dzoukr
10

Saya mengalami masalah yang sama persis dan solusinya ternyata cukup mudah bagi saya. Pada dasarnya ubah kode Anda menjadi yang berikut dan seharusnya berfungsi. CATATAN: pengembalian sebelum gulp.src membuat semua perbedaan bagi saya.

gulp.task "coffee", ->
    return gulp.src("src/server/**/*.coffee")
        .pipe(coffee {bare: true}).on("error",gutil.log)
        .pipe(gulp.dest "bin")

gulp.task "clean",->
    return gulp.src("bin", {read:false})
        .pipe clean
            force:true

gulp.task 'develop',['clean','coffee'], ->
    console.log "run something else"
CPP
sumber
Terima kasih atas catatan untuk kembali! Apakah gila mencoba mencari tahu mengapa menelan itu tugas-tugas rusak.
Andrew F
Ini harus menjadi jawaban yang benar untuk menghindari hubungan yang erat antara tugas. Bekerja dengan baik. gulp.series tersedia di 4.0 mungkin merupakan jawaban terbaik, tetapi sampai hari ini, 4.0 tidak tersedia.
wilk
tegukan berkembang akan berjalan bersih atau kopi pertama
scape
8

mencoba semua solusi yang diusulkan, semua tampaknya memiliki masalah sendiri.

Jika Anda benar-benar melihat ke sumber Orchestrator, khususnya .start() implementasinya Anda akan melihat bahwa jika parameter terakhir adalah suatu fungsi, ia akan memperlakukannya sebagai panggilan balik.

Saya menulis cuplikan ini untuk tugas saya sendiri:

  gulp.task( 'task1', () => console.log(a) )
  gulp.task( 'task2', () => console.log(a) )
  gulp.task( 'task3', () => console.log(a) )
  gulp.task( 'task4', () => console.log(a) )
  gulp.task( 'task5', () => console.log(a) )

  function runSequential( tasks ) {
    if( !tasks || tasks.length <= 0 ) return;

    const task = tasks[0];
    gulp.start( task, () => {
        console.log( `${task} finished` );
        runSequential( tasks.slice(1) );
    } );
  }
  gulp.task( "run-all", () => runSequential([ "task1", "task2", "task3", "task4", "task5" ));
Assaf Moldavsky
sumber
4

Saya mencari jawaban ini sebentar. Sekarang saya mendapatkannya di dokumentasi tegukan resmi.

Jika Anda ingin melakukan tugas tegukan saat yang terakhir selesai, Anda harus mengembalikan aliran:

gulp.task('wiredep', ['dev-jade'], function () {
    var stream = gulp.src(paths.output + '*.html')
        .pipe($.wiredep())
        .pipe(gulp.dest(paths.output));

    return stream; // execute next task when this is completed
});

// First will execute and complete wiredep task
gulp.task('prod-jade', ['wiredep'], function() {
    gulp.src(paths.output + '**/*.html')
        .pipe($.minifyHtml())
        .pipe(gulp.dest(paths.output));
});

Lucho Suárez
sumber
3

Cukup buat coffeeketergantungan clean, dan developbergantung pada coffee:

gulp.task('coffee', ['clean'], function(){...});
gulp.task('develop', ['coffee'], function(){...});

Pengiriman sekarang berseri: cleancoffeedevelop. Perhatikan bahwa cleanimplementasi dan coffeeimplementasi harus menerima panggilan balik, "jadi mesin tahu kapan akan dilakukan" :

gulp.task('clean', function(callback){
  del(['dist/*'], callback);
});

Kesimpulannya, di bawah ini adalah pola menelan sederhana untuk sinkron cleandiikuti oleh dependensi build asinkron :

//build sub-tasks
gulp.task('bar', ['clean'], function(){...});
gulp.task('foo', ['clean'], function(){...});
gulp.task('baz', ['clean'], function(){...});
...

//main build task
gulp.task('build', ['foo', 'baz', 'bar', ...], function(){...})

Gulp cukup pintar untuk berjalan cleantepat sekali per build, tidak peduli berapa banyak buildketergantungan tergantung clean. Seperti yang ditulis di atas, cleanadalah penghalang sinkronisasi, maka semua builddependensi berjalan secara paralel, kemudian buildberjalan.

akarve
sumber
3

Bagi saya itu tidak menjalankan tugas minify setelah concatenation karena mengharapkan input concatenated dan tidak dihasilkan beberapa kali.

Saya mencoba menambah tugas default dalam urutan eksekusi dan tidak berhasil. Ini berhasil setelah menambahkan hanya returnuntuk setiap tugas dan mendapatkan minifikasi di dalam gulp.start()seperti di bawah ini.

/**
* Concatenate JavaScripts
*/
gulp.task('concat-js', function(){
    return gulp.src([
        'js/jquery.js',
        'js/jquery-ui.js',
        'js/bootstrap.js',
        'js/jquery.onepage-scroll.js',
        'js/script.js'])
    .pipe(maps.init())
    .pipe(concat('ux.js'))
    .pipe(maps.write('./'))
    .pipe(gulp.dest('dist/js'));
});

/**
* Minify JavaScript
*/
gulp.task('minify-js', function(){
    return gulp.src('dist/js/ux.js')
    .pipe(uglify())
    .pipe(rename('ux.min.js'))
    .pipe(gulp.dest('dist/js'));
});

gulp.task('concat', ['concat-js'], function(){
   gulp.start('minify-js');
});

gulp.task('default',['concat']); 

Sumber http://schickling.me/synchronous-tasks-gulp/

devo
sumber
2

Tegp dan Node menggunakan janji .

Jadi Anda bisa melakukan ini:

// ... require gulp, del, etc

function cleanTask() {
  return del('./dist/');
}

function bundleVendorsTask() {
  return gulp.src([...])
    .pipe(...)
    .pipe(gulp.dest('...'));
}

function bundleAppTask() {
  return gulp.src([...])
    .pipe(...)
    .pipe(gulp.dest('...'));
}

function tarTask() {
  return gulp.src([...])
    .pipe(...)
    .pipe(gulp.dest('...'));
}

gulp.task('deploy', function deployTask() {
  // 1. Run the clean task
  cleanTask().then(function () {
    // 2. Clean is complete. Now run two tasks in parallel
    Promise.all([
      bundleVendorsTask(),
      bundleAppTask()
    ]).then(function () {
      // 3. Two tasks are complete, now run the final task.
      tarTask();
    });
  });
});

Jika Anda mengembalikan aliran tegukan, Anda dapat menggunakan then()metode ini untuk menambahkan panggilan balik. Sebagai alternatif, Anda dapat menggunakan Node's native Promiseuntuk membuat janji Anda sendiri. Di sini saya gunakan Promise.all()untuk memiliki satu panggilan balik yang menyala ketika semua janji terselesaikan.

Peter J. Hart
sumber
-8

Coba retasan ini :-) Gulp v3.x Retas untuk bug Async

Saya mencoba semua cara "resmi" di Readme, mereka tidak bekerja untuk saya tetapi ini berhasil. Anda juga dapat memutakhirkan ke tegukan 4.x tapi saya sangat menyarankan Anda tidak, itu merusak banyak hal. Anda bisa menggunakan janji js asli, tapi hei, ini cepat, kotor, sederhana :-) Pada dasarnya Anda menggunakan:

var wait = 0; // flag to signal thread that task is done
if(wait == 0) setTimeout(... // sleep and let nodejs schedule other threads

Lihat posnya!

Will Bittner
sumber
Ada cara yang lebih baik untuk menyelesaikan masalah, menggunakan setTimeout tidak sesuai. Anda tidak bisa tahu persis berapa banyak waktu yang dibutuhkan untuk menyelesaikan suatu tugas.
Reginaldo Camargo Ribeiro
Anda benar-benar harus berpikir sebelum Anda menulis kode apa pun pff
DDD