So führen Sie Gulp-Aufgaben nacheinander aus

398

im Snippet wie folgt:

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"

In der developAufgabe möchte ich ausführen cleanund nachdem es erledigt ist, laufen coffeeund wenn das erledigt ist, etwas anderes ausführen. Aber das kann ich nicht herausfinden. Dieses Stück funktioniert nicht. Bitte beraten.

iLemming
quelle
10
Das Run-Sequence-npm-Modul behebt dieses Problem jetzt - alle anderen Antworten sind jetzt irrelevant - siehe die Antwort von
OverZealous
1
Gulp 4.0 unterstützt nativ das Ausführen von Aufgaben nacheinander und macht sie run-sequenceobsolet - siehe Massanishis Antwort unten
Forivin
Gulp4 bricht anscheinend mehr Dinge, als es behebt. Nachdem ich einige Stunden damit gekämpft habe, bin ich zurück zu 3.9.1. Mir ist klar, dass Hauptversionen Backcompat unterbrechen können / werden, aber mit kryptischen und nutzlosen Fehlermeldungen sage ich nein, danke. v4 ist nicht bereit.
Sa Thiru

Antworten:

121

Es ist noch keine offizielle Version, aber mit Gulp 4.0 können Sie problemlos synchrone Aufgaben mit gulp.series ausführen. Sie können es einfach so machen:

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

Ich habe einen guten Blog-Beitrag gefunden, in dem vorgestellt wird, wie man diese netten Funktionen aktualisiert und nutzt: die Migration auf gulp 4 anhand eines Beispiels

Massanishi
quelle
3
Methode der Wahl für alle Neuankömmlinge. Sie sollten wirklich mit Schluck 4 beginnen und alle 3. * Probleme und eine große Auswahl an Antimustern überspringen.
Metalim
187
Es ist 2017 und sie haben es immer noch nicht eingeführt. Großartig.
Tomasz Mularczyk
14
Ich verstehe den Punkt wirklich nicht. Wenn A unbedingt erst nach B ausgeführt werden muss, hängt A von B ab. Warum können Sie nicht einfach angeben, dass B eine Abhängigkeit von A ist? gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
musicin3d
3
@ musicin3d Was Sie sagen, funktioniert, aber Sie koppeln eine Aufgabe unbedingt mit der vorherigen. Zum Beispiel möchte ich bauen können, ohne vorher immer fusseln zu müssen. Es ist eine bessere Lösung, unabhängige Aufgaben zu haben und die Reihenfolge der Ausführung mit einem externen Tool zu bestimmen.
AxeEffect
11
Es ist 2018 und sie haben es endlich eingeführt. Großartig.
Dargmuesli
411

Standardmäßig führt gulp Aufgaben gleichzeitig aus, sofern sie keine expliziten Abhängigkeiten aufweisen. Dies ist nicht sehr nützlich für Aufgaben wie clean, bei denen Sie nicht abhängig sein möchten, diese aber vor allem anderen ausgeführt werden müssen.

Ich habe das run-sequencePlugin speziell geschrieben, um dieses Problem mit gulp zu beheben. Verwenden Sie es nach der Installation folgendermaßen:

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

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

Sie können die vollständigen Anweisungen auf dem Paket README lesen - es unterstützt auch das gleichzeitige Ausführen einiger Aufgabensätze.

Bitte beachten Sie, dass dies in der nächsten Hauptversion von gulp (effektiv) behoben wird , da die automatische Reihenfolge der Abhängigkeiten vollständig beseitigt wird und ähnliche Tools bereitgestellt werden, run-sequencemit denen Sie die gewünschte Ausführungsreihenfolge manuell festlegen können.

Dies ist jedoch eine wichtige Änderung, sodass es keinen Grund gibt, zu warten, bis Sie sie run-sequenceheute verwenden können.

Übereifrig
quelle
2
@OverZealous danke für das Plugin! Übrigens hat das gulp-cleanPlugin Streams 2 nicht implementiert, daher gab es Probleme, die als Abhängigkeiten ausgeführt wurden. Dies wurde ab Release Version 0.3.0 behoben. Mein Mitarbeiter hat eine PR eingereicht, um sie zu konvertieren.
bekanntasilya
3
Der @Indolering integrierte Taskabhängigkeits Funktionalität ist nicht löst dieses Szenario. Abhängige Aufgaben werden immer ausgeführt: Es gibt keine in Art und Weise errichtet wird zwei Aufgaben in einer Reihe laufen einige der Zeit, aber nicht jedes Mal. run-sequencelöst ein kritisches Stück fehlender Funktionalität in gulp.
OverZealous
2
Außerdem sind Aufgabenabhängigkeiten keine vollständige Lösung. Angenommen, ich habe zwei Schluckaufgaben, die unabhängig voneinander Tests mit der Datenbank ausführen. Keiner ist vom anderen abhängig, aber ich möchte nicht, dass einer von ihnen gleichzeitig ausgeführt wird, da beide die Datenbank verwenden müssen.
Peterjwest
3
Erstaunliches Modul - Hier ist eine großartige Erklärung, warum es benötigt wird - blog.mdnbar.com/gulp-for-simple-build-proccess - Dies sollte die akzeptierte Antwort sein
danday74
5
Ich bin dankbar, dass Sie eine Lösung dafür gefunden haben, aber es ist absurd, dass wir zusätzliche Werkzeuge benötigen, um eine sequentielle Ausführung zu erhalten. Sequentielle Ausführung sollte die Standardeinstellung sein oder zumindest verdammt einfach. Makefiles werden seit 40 Jahren sequentiell ausgeführt. Das JS-Ökosystem macht mich krank. 73 Megabyte node_modules, nur um ein Boilerplate-Projekt ohne Features zu kompilieren, und das beinhaltet immer noch nicht die Fähigkeit zur sequentiellen Ausführung. Betriebssysteme passen auf kleinerem Raum und haben Kernel und Treiber-FFS.
joonas.fi
371

Die einzig gute Lösung für dieses Problem finden Sie in der Schluckdokumentation, die Sie hier finden

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é
quelle
6
Aus irgendeinem Grund ReferenceError: err is not definedversuche ich, dies für eine gulp-compassAufgabe auszuführen. Vermisse ich etwas?
Waffel
11
@waffl In diesem Beispiel wird ein Rückruf verwendet. Dies ist nicht die einzige Möglichkeit, dies zu tun. Gemäß den Dokumenten können Sie auch "ein Versprechen oder einen Stream zurückgeben, dass die Engine warten soll, bis sie aufgelöst oder beendet ist". Wenn Sie also einen Stream in Aufgabe eins zurückgeben, z. B. return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');besteht der Schlüssel darin, Aufgabe eins als abhängig zu identifizieren, wenn Sie Aufgabe zwei definieren: gulp.task('two', ['one'], function() {... Aufgabe zwei wartet nun auf das Ende von Aufgabe eins, bevor sie ausgeführt wird.
Esvendsen
24
Dies schafft eine enge Kopplung zwischen 'eins' und 'zwei'. Was ist, wenn Sie "zwei" ausführen möchten, ohne "eins" auszuführen
wilk
5
Sie definieren eine neue Aufgabe ohne die Abhängigkeit?
Mathieu Borderé
8
Wenn zwei Aufgaben nacheinander ausgeführt werden müssen, ist eine enge Kopplung erforderlich.
Ringo
56

Ich habe eine Node / Gulp-App mit dem Generator-gulp-webapp Yeoman-Generator generiert . Es handhabte das "saubere Rätsel" auf diese Weise (übersetzt in die ursprünglichen Aufgaben, die in der Frage erwähnt wurden):

gulp.task('develop', ['clean'], function () {
  gulp.start('coffee');
});
Steve
quelle
2
Dies war genau das (und sehr einfache), was ich brauchte. Es befasst sich mit dem Szenario, in dem ich so etwas wie eine Bereinigung als vorhergehende Abhängigkeit ausführen muss, um Abhängigkeiten zu erstellen, ohne eine Bereinigung als Abhängigkeit für diese Aufgaben festzulegen. PS: Info über die gulp.start () Bit - Vorbehalt
Emptor
Das macht Sinn; Ein Rückruf nach Abschluss der Hauptaufgabe (und ihrer abhängigen Aufgaben). Vielen Dank.
Markau
4
Wenn sich jemand fragt, warum es keine offizielle Dokumentation dafür gibt gulp.start(), erklärt diese Antwort von gulp member gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it
Folgendes
1
Wie kann ich in diesem Fall feststellen, dass die coffeeAufgabe abgeschlossen ist? Wenn ich es nicht developcoffee
erkenne
habe bereits die Antwort vom run-sequenceQuellcode erhalten : gulp.on('task_stop'). Siehe meine erweiterte Antwort für Details: stackoverflow.com/a/38818657/3027390
thybzi
32

Run-Sequence ist der klarste Weg (zumindest bis Gulp 4.0 veröffentlicht wird)

Mit run-sequence sieht Ihre Aufgabe folgendermaßen aus:

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

Aber wenn Sie (aus irgendeinem Grund) es vorziehen, es nicht zu verwenden, gulp.starthilft die Methode :

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

Hinweis: Wenn Sie die Aufgabe nur starten, ohne auf das Ergebnis zu hören, wird die developAufgabe früher als beendet coffee, was verwirrend sein kann.

Sie können den Ereignis-Listener auch entfernen, wenn er nicht benötigt wird

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

Bedenken Sie, dass es auch ein task_errEreignis gibt, das Sie möglicherweise anhören möchten. task_stopwird bei erfolgreichem Abschluss ausgelöst und task_errerscheint, wenn ein Fehler vorliegt.

Sie fragen sich vielleicht auch, warum es keine offizielle Dokumentation für gibt gulp.start(). Diese Antwort von gulp member erklärt die Dinge:

gulp.start ist absichtlich undokumentiert, da dies zu komplizierten Build-Dateien führen kann und wir nicht möchten, dass Benutzer sie verwenden

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

Thybzi
quelle
zwei Kaffees an diesen Mann! Die Lösung mit dem Entfernen des Listeners funktioniert einfach perfekt!
daniel.bavrin
Dies ist wirklich die Antwort oder einfach "schlucken 4". Die Laufsequenz ist robust.
LAdams87
26

Laut den Gulp-Dokumenten:

Werden Ihre Aufgaben ausgeführt, bevor die Abhängigkeiten abgeschlossen sind? Stellen Sie sicher, dass Ihre Abhängigkeitsaufgaben die asynchronen Ausführungshinweise korrekt verwenden: Nehmen Sie einen Rückruf auf oder geben Sie ein Versprechen oder einen Ereignisstrom zurück.

So führen Sie Ihre Aufgabenfolge synchron aus:

  1. Geben Sie den Ereignisstrom (z. B. gulp.src) an zurück gulp.task, um die Aufgabe darüber zu informieren, wann der Strom endet.
  2. Deklarieren Sie Aufgabenabhängigkeiten im zweiten Argument von gulp.task.

Siehe den überarbeiteten Code:

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
quelle
4
DAS sollte die richtige Antwort sein! Die Rückkehr der Aufgabe hat es geschafft! Danke, Mann.
Dzoukr
10

Ich hatte genau das gleiche Problem und die Lösung erwies sich für mich als ziemlich einfach. Ändern Sie Ihren Code grundsätzlich wie folgt und es sollte funktionieren. HINWEIS: Die Rückkehr vor gulp.src hat für mich den Unterschied ausgemacht.

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
quelle
Vielen Dank für den Hinweis bei der Rückkehr! War verrückt geworden, um herauszufinden, warum das Schlucken die Aufgaben nicht in Ordnung brachte.
Andrew F
Dies sollte die richtige Antwort sein, um eine enge Kopplung zwischen den Aufgaben zu vermeiden. Funktioniert gut. gulp.series in 4.0 ist wahrscheinlich die beste Antwort, aber derzeit ist 4.0 nicht verfügbar.
Wilk
Schluck entwickeln wird sauber laufen oder Kaffee zuerst
scape
8

probierte alle vorgeschlagenen Lösungen aus, alle scheinen ihre eigenen Probleme zu haben.

Wenn Sie sich tatsächlich die Orchestrator-Quelle ansehen, insbesondere die .start()Implementierung, werden Sie feststellen, dass der letzte Parameter, wenn er eine Funktion ist, als Rückruf behandelt wird.

Ich habe diesen Ausschnitt für meine eigenen Aufgaben geschrieben:

  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
quelle
4

Ich habe eine Weile nach dieser Antwort gesucht. Jetzt habe ich es in der offiziellen Schluckdokumentation bekommen.

Wenn Sie eine Schluckaufgabe ausführen möchten, wenn die letzte abgeschlossen ist, müssen Sie einen Stream zurückgeben:

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
quelle
3

Einfach coffeeabhängig machen von cleanund developabhängig von coffee:

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

Der Versand erfolgt jetzt seriell: cleancoffeedevelop. Beachten Sie, dass cleandie Implementierung und coffeedie Implementierung einen Rückruf akzeptieren müssen , "damit die Engine weiß, wann dies geschehen wird" :

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

Im Folgenden finden Sie ein einfaches Schluckmuster für eine synchrone, cleangefolgt von asynchronen Build-Abhängigkeiten :

//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 ist intelligent genug, um cleangenau einmal pro ausgeführt zu werden build, unabhängig davon, von wie vielen buildAbhängigkeiten dies abhängt clean. Wie oben beschrieben, cleanhandelt es sich um eine Synchronisationsbarriere. Anschließend werden alle buildAbhängigkeiten parallel ausgeführt und anschließend ausgeführt build.

akarve
quelle
3

Für mich wurde die Minify-Task nach der Verkettung nicht ausgeführt, da sie verkettete Eingaben erwartet und einige Male nicht generiert wurde.

Ich habe versucht, eine Standardaufgabe in der Ausführungsreihenfolge hinzuzufügen, aber es hat nicht funktioniert. Es funktionierte, nachdem nur ein returnfür jede Aufgabe hinzugefügt und die Minimierung gulp.start()wie unten beschrieben ausgeführt wurde.

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

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

devo
quelle
2

Gulp und Node verwenden Versprechen .

So können Sie Folgendes tun:

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

Wenn Sie den Gulp-Stream zurückgeben, können Sie mit dieser then()Methode einen Rückruf hinzufügen. Alternativ können Sie Node's Native verwenden Promise, um Ihre eigenen Versprechen zu erstellen. Hier habe ich Promise.all()einen Rückruf, der ausgelöst wird, wenn alle Versprechen gelöst sind.

Peter J. Hart
quelle
-8

Versuchen Sie diesen Hack :-) Gulp v3.x Hack für Async-Fehler

Ich habe alle "offiziellen" Methoden in der Readme-Datei ausprobiert. Sie haben bei mir nicht funktioniert, aber das hat funktioniert. Sie können auch auf gulp 4.x upgraden, aber ich empfehle Ihnen dringend, dies nicht zu tun, da es so viel kaputt macht. Sie könnten ein echtes js-Versprechen gebrauchen, aber hey, das ist schnell, schmutzig, einfach :-) Im Wesentlichen verwenden Sie:

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

Schauen Sie sich den Beitrag an!

Will Bittner
quelle
Es gibt bessere Möglichkeiten, um das Problem zu lösen. Die Verwendung von setTimeout ist nicht geeignet. Sie konnten nicht genau wissen, wie viel Zeit eine Aufgabe in Anspruch nehmen wird.
Reginaldo Camargo Ribeiro
Sie sollten wirklich überlegen, bevor Sie einen Code pff
DDD