Come eseguire le attività di Gulp in sequenza una dopo l'altra


398

nello snippet in questo modo:

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"

Nel developcompito voglio correre cleane dopo che è finito, corri coffeee quando fatto, esegui qualcos'altro. Ma non riesco a capirlo. Questo pezzo non funziona. Si prega di avvisare.


10
Il modulo npm della sequenza di esecuzione risolve questo problema ora - tutte le altre risposte sono ora irrilevanti - vedi la risposta di OverZealous di seguito
danday74

1
Gulp 4.0 supporta nativamente l'esecuzione di attività in sequenza, rendendola run-sequenceobsoleta - vedi la risposta di massanishi di seguito
Forivin

A quanto pare, Gulp4 rompe più cose di quante ne risolva. Dopo aver combattuto per alcune ore, torno al 3.9.1. Mi rendo conto che le versioni principali possono / rompono il backcompat ma con messaggi di errore criptici e inutili, dico di no grazie. v4 non è pronto.
Sab Thiru,

Risposte:


121

Non è ancora una versione ufficiale, ma la prossima versione di Gulp 4.0 consente di eseguire facilmente attività sincrone con gulp.series. Puoi semplicemente farlo in questo modo:

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

Ho trovato un buon post sul blog che introduce come aggiornare e utilizzare quelle funzionalità pulite: migrare a gulp 4 con l'esempio


3
Metodo di scelta per tutti i nuovi arrivati. Dovrebbero davvero iniziare con gulp 4, saltando tutte le seccature 3. * e una vasta gamma di antipattern.
metalim,

187
è il 2017 e non lo hanno ancora introdotto. Grande.
Tomasz Mularczyk,

14
Non vedo il punto, davvero. Se devi assolutamente eseguire A solo dopo l'esecuzione di B, allora A dipende da B. Perché non puoi semplicemente specificare che B è una dipendenza di A? gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
musicin3d

3
@ musicin3d Quello che dici funziona, ma stai accoppiando un compito necessariamente al precedente. Ad esempio, voglio essere in grado di costruire senza dover sempre sfilacciare prima. È una soluzione migliore per avere compiti indipendenti e decidere l'ordine di esecuzione con uno strumento esterno.
AxeEffect,

11
è il 2018 e finalmente lo hanno introdotto. Grande.
dargmuesli,

411

Per impostazione predefinita, gulp esegue le attività contemporaneamente, a meno che non abbiano dipendenze esplicite. Questo non è molto utile per attività come clean, in cui non si desidera dipendere, ma è necessario che vengano eseguite prima di ogni altra cosa.

Ho scritto il run-sequenceplugin appositamente per risolvere questo problema con gulp. Dopo averlo installato, utilizzalo in questo modo:

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

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

Puoi leggere le istruzioni complete sul pacchetto README - supporta anche l'esecuzione di alcuni set di attività contemporaneamente.

Si noti che questo sarà risolto (in modo efficace) nella prossima versione principale di gulp , poiché eliminano completamente l'ordinamento automatico delle dipendenze e forniscono strumenti simili run-sequenceper consentire all'utente di specificare manualmente l'ordine di esecuzione come desiderato.

Tuttavia, questo è un grande cambiamento, quindi non c'è motivo di aspettare quando puoi usarlo run-sequenceoggi.


2
@OverZealous grazie per il plugin! A proposito, il gulp-cleanplugin non stava implementando Streams 2, quindi aveva problemi a funzionare come dipendenze. Questo problema è stato risolto a partire dalla versione 0.3.0, il mio collega ha inviato un PR per convertirlo.
knownasilya,

3
@Indolering La funzionalità di dipendenza attività integrata non risolve questo scenario. Le attività dipendenti vengono sempre eseguite: non esiste un modo integrato per eseguire due attività di seguito alcune volte, ma non tutte le volte. run-sequencerisolve un pezzo critico di funzionalità mancante in gulp.
Troppo zelante il

2
Inoltre, le dipendenze delle attività non sono una soluzione completa. Supponiamo che io abbia due compiti gulp che eseguono in modo indipendente test usando il database. Nessuno dei due dipende dall'altro, ma non voglio che entrambi vengano eseguiti contemporaneamente perché entrambi devono utilizzare il database.
peterjwest,

3
Modulo straordinario - Ecco una grande spiegazione del perché è necessario - blog.mdnbar.com/gulp-for-simple-build-proccess - Questa dovrebbe essere la risposta accettata
danday74

5
Sono grato che tu abbia fatto una soluzione per questo, ma è assurdo che abbiamo bisogno di strumenti aggiuntivi per ottenere l'esecuzione sequenziale. L'esecuzione sequenziale dovrebbe essere quella predefinita, o almeno fottutamente facile da fare. I makefile hanno avuto un'esecuzione sequenziale da 40 anni. L'ecosistema JS mi fa star male. 73 megabyte di node_modules solo per compilare un progetto boilerplate senza alcuna funzionalità e che non include ancora la capacità di esecuzione sequenziale. I sistemi operativi si adattano in uno spazio più piccolo e hanno kernel e driver FFS.
joonas.fi,

371

L'unica buona soluzione a questo problema si trova nella documentazione gulp che può essere trovata qui

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

6
Per qualche motivo sto ReferenceError: err is not definedprovando a eseguire questo su gulp-compassun'attività, mi sto perdendo qualcosa?
waffl,

11
@waffl in questo esempio usa un callback, che non è l'unico modo per farlo. Secondo i documenti , puoi anche "restituire una promessa o un flusso che il motore dovrebbe attendere per risolvere o terminare rispettivamente". Pertanto, se si restituisce un flusso nell'attività uno, ad esempio return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');, la chiave è identificare l'attività uno come dipendente quando si definisce l'attività due: L' gulp.task('two', ['one'], function() {... attività due ora attende che l'attività uno termini prima di essere eseguita.
esvendsen,

24
Questo crea un accoppiamento stretto tra 'uno' e 'due'. Che cosa succede se si desidera eseguire 'due' senza eseguire 'uno'
wilk

5
definisci una nuova attività senza la dipendenza?
Mathieu Borderé,

8
La necessità di eseguire due attività in sequenza implica un accoppiamento stretto.
Ringo,

56

Ho generato un'app nodo / gulp usando il generatore Yeoman generator -gulp-webapp . Ha gestito il "enigma pulito" in questo modo (traducendo nei compiti originali menzionati nella domanda):

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

2
Questo era l'esatto (e molto semplice) di cui avevo bisogno. Affronta lo scenario in cui ho bisogno di fare qualcosa di simile a una pulizia come una precedente dipendenza per creare dipendenze senza impostare clean come una dipendenza per quelle attività. PS: Informazioni sul bit gulp.start () - avvertimento: github.com/gulpjs/gulp/issues/426
Jaans

Questo ha senso; una richiamata dopo che l'attività principale (e le sue attività dipendenti) sono state completate. Grazie.
markau,

4
Se qualcuno si chiede perché non ci sia documentazione ufficiale per gulp.start(), questa risposta del membro gulp spiega che: gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it(fonte: github.com/gulpjs/gulp/issues/426#issuecomment-41208007 )
thybzi

1
In questo caso, come posso rilevare che l' coffeeattività è terminata? Se non lo developcoffee
rilevo

già ottenuto la risposta dal run-sequencecodice sorgente: gulp.on('task_stop'). Vedere la mia risposta estesa per i dettagli: stackoverflow.com/a/38818657/3027390
thybzi

32

la sequenza di esecuzione è il modo più chiaro (almeno fino al rilascio di Gulp 4.0)

Con la sequenza di esecuzione , l'attività sarà simile alla seguente:

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

Ma se tu (per qualche ragione) preferisci non usarlo, il gulp.startmetodo ti aiuterà :

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

Nota: se si avvia un'attività solo senza ascoltare il risultato, l' developattività terminerà prima di coffeee ciò potrebbe creare confusione.

È inoltre possibile rimuovere il listener di eventi quando non è necessario

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

Considera che c'è anche un task_errevento che potresti voler ascoltare. task_stopviene attivato al termine, mentre task_errviene visualizzato in caso di errore.

Potresti anche chiederti perché non esiste una documentazione ufficiale per gulp.start(). Questa risposta del membro di Gulp spiega le cose:

gulp.start non è documentato apposta perché può portare a file di build complicati e non vogliamo che le persone lo utilizzino

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


due caffè a quest'uomo! la soluzione con la rimozione dell'ascoltatore funziona perfettamente!
daniel.bavrin,

Questa è davvero la risposta, o semplicemente "gulp 4". La sequenza di esecuzione è robusta.
LAdams87,

26

Secondo i documenti di Gulp:

Le attività sono in esecuzione prima del completamento delle dipendenze? Assicurarsi che le attività di dipendenza stiano utilizzando correttamente i suggerimenti per l'esecuzione asincrona: accettare una richiamata o restituire un flusso di promesse o eventi.

Per eseguire la sequenza di attività in modo sincrono:

  1. Riporta il flusso di eventi (ad es. gulp.src) Agulp.task Per informare l'attività di quando termina il flusso.
  2. Dichiarare le dipendenze delle attività nel secondo argomento di gulp.task.

Vedi il codice rivisto:

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"

4
QUESTA dovrebbe essere la risposta corretta! Il compito di ritorno ha fatto il trucco! Grazie uomo.
Dzoukr,

10

Avevo lo stesso identico problema e la soluzione si è rivelata abbastanza facile per me. In sostanza, modifica il codice nel modo seguente e dovrebbe funzionare. NOTA: il ritorno prima di gulp.src ha fatto la differenza per me.

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"

Grazie per la nota sul ritorno! Stava andando fuori di testa cercando di capire perché Gulp stava eseguendo compiti fuori servizio.
Andrew F,

Questa dovrebbe essere la risposta corretta per evitare uno stretto accoppiamento tra compiti. Funziona bene. gulp.series disponibile in 4.0 è probabilmente la risposta migliore, ma ad oggi 4.0 non è disponibile.
Wilson,

gulp develop funzionerà pulito o prima il caffè
scape

8

provato tutte le soluzioni proposte, tutte sembrano avere problemi propri.

Se si esamina effettivamente l'origine dell'orchestrator, in particolare il .start() implementazione, si vedrà che se l'ultimo parametro è una funzione, lo tratterà come un callback.

Ho scritto questo frammento per i miei compiti:

  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" ));

4

Stavo cercando questa risposta per un po '. Ora l'ho preso nella documentazione ufficiale di gulp.

Se si desidera eseguire un'attività gulp al termine dell'ultima, è necessario restituire uno stream:

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


3

Basta fare coffeeaffidamento cleane developdipendere da coffee:

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

La spedizione è ora seriale: cleancoffeedevelop. Si noti che cleanl'implementazione e coffeel'implementazione devono accettare un callback, "in modo che il motore sappia quando verrà eseguito" :

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

In conclusione, di seguito è riportato un semplice modello gulp per un sincrono cleanseguito da dipendenze di build asincrone :

//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 è abbastanza intelligente da funzionare cleanesattamente una volta per build, indipendentemente da quante builddipendenze dipendono clean. Come scritto sopra, cleanè una barriera di sincronizzazione, quindi tutte buildle dipendenze vengono eseguite in parallelo, quindi buildviene eseguita.


3

Per me non stava eseguendo l'attività di minimizzazione dopo la concatenazione in quanto prevede input concatenati e non è stato generato alcune volte.

Ho provato ad aggiungere un'attività predefinita in ordine di esecuzione e non ha funzionato. Ha funzionato dopo aver aggiunto solo un returnper ogni attività e ottenere la minificazione all'interno gulp.start()come di seguito.

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

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


2

Gulp e Node usano le promesse .

Quindi puoi farlo:

// ... 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();
    });
  });
});

Se si restituisce il flusso gulp, è possibile utilizzare il then()metodo per aggiungere un callback. In alternativa, puoi usare il nativo di Node Promiseper creare le tue promesse. Qui uso Promise.all()una callback che si attiva quando tutte le promesse si risolvono.


-8

Prova questo trucco :-) Gulp v3.x Hack for Async bug

Ho provato tutti i modi "ufficiali" nel Readme, non hanno funzionato per me, ma questo ha funzionato. Puoi anche aggiornare a gulp 4.x ma ti consiglio vivamente di non farlo, si rompe così tante cose. Potresti usare una vera promessa di js, ma ehi, questo è veloce, sporco, semplice :-) In sostanza usi:

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

Dai un'occhiata al post!


Esistono modi migliori per risolvere il problema, l'utilizzo di setTimeout non è appropriato. Non puoi sapere esattamente quanto tempo ci vorrà per terminare un'attività.
Reginaldo Camargo Ribeiro,

Dovresti davvero pensare prima di scrivere qualsiasi codice pff
DDD,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.