Làm thế nào để chạy các nhiệm vụ Gulp lần lượt


398

trong đoạn trích như thế này:

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"

Trong developnhiệm vụ tôi muốn chạy cleanvà sau khi hoàn thành, chạy coffeevà khi hoàn thành, hãy chạy một cái gì đó khác. Nhưng tôi không thể tìm ra điều đó. Phần này không hoạt động. Xin tư vấn.


10
Mô-đun npm chuỗi chạy khắc phục sự cố này ngay bây giờ - tất cả các câu trả lời khác hiện không liên quan - xem câu trả lời của OverZealous bên dưới
danday74

1
Gulp 4.0 vốn hỗ trợ các tác vụ đang chạy theo trình tự, khiến cho run-sequencelỗi thời - xem câu trả lời hàng loạt bên dưới
Forivin

Gulp4 phá vỡ nhiều thứ hơn nó sửa chữa, có vẻ như. Sau khi chiến đấu với nó trong vài giờ, tôi trở lại 3.9.1. Tôi nhận ra các phiên bản chính có thể / sẽ phá vỡ backcompat nhưng với các thông báo lỗi khó hiểu và vô dụng, tôi nói không, cảm ơn. v4 chưa sẵn sàng.
Sat Thiru

Câu trả lời:


121

Đây chưa phải là một bản phát hành chính thức, nhưng Gulp 4.0 sắp tới cho phép bạn dễ dàng thực hiện các tác vụ đồng bộ với gulp.series. Bạn có thể chỉ cần làm như thế này:

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

Tôi tìm thấy một bài đăng blog tốt giới thiệu cách nâng cấp và sử dụng các tính năng gọn gàng đó: di chuyển sang gulp 4 bằng ví dụ


3
Phương pháp lựa chọn cho tất cả những người mới. Họ nên thực sự bắt đầu với gulp 4, bỏ qua tất cả 3. * rắc rối và phạm vi rộng của các phản hạt.
metalim

187
năm 2017 và họ vẫn chưa giới thiệu nó. Tuyệt quá.
Tomasz Mularchot

14
Tôi không thấy vấn đề, thực sự. Nếu bạn thực sự cần A chỉ chạy sau khi B chạy, thì A phụ thuộc vào B. Tại sao bạn không thể chỉ định B là phụ thuộc của A? gulp.task('coffee', ['clean'], function(){...}); gulp.task('develop', ['coffee']);
musicin3d

3
@ musicin3d Những gì bạn nói hoạt động, nhưng bạn cần kết hợp một nhiệm vụ nhất thiết với trước đó. Ví dụ, tôi muốn có thể xây dựng mà không phải luôn luôn lint trước. Đó là một giải pháp tốt hơn để có các nhiệm vụ độc lập và quyết định thứ tự thực hiện với một công cụ bên ngoài.
AxeEffect

11
năm 2018 và cuối cùng họ đã giới thiệu nó. Tuyệt quá.
dargmuesli

411

Theo mặc định, gulp chạy các tác vụ đồng thời, trừ khi chúng có phụ thuộc rõ ràng. Điều này không hữu ích cho các nhiệm vụ như clean, nơi bạn không muốn phụ thuộc, nhưng bạn cần chúng để chạy trước mọi thứ khác.

Tôi đã viết các run-sequencePlugin đặc biệt để khắc phục vấn đề này với ngụm. Sau khi bạn cài đặt nó, sử dụng nó như thế này:

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

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

Bạn có thể đọc hướng dẫn đầy đủ trên gói README - nó cũng hỗ trợ chạy đồng thời một số bộ tác vụ.

Xin lưu ý, điều này sẽ được khắc phục (một cách hiệu quả) trong bản phát hành chính tiếp theo của gulp , vì chúng loại bỏ hoàn toàn thứ tự phụ thuộc tự động và cung cấp các công cụ tương tự run-sequenceđể cho phép bạn chỉ định thủ công chạy theo cách bạn muốn.

Tuy nhiên, đó là một thay đổi lớn, vì vậy không có lý do gì để chờ đợi khi bạn có thể sử dụng run-sequencengay hôm nay.


2
@OverZealous cảm ơn các plugin! Btw, gulp-cleanplugin không triển khai Streams 2, do đó, nó có vấn đề đang được chạy như một phần phụ thuộc. Điều này đã được sửa chữa kể từ phiên bản phát hành 0.3.0, đồng nghiệp của tôi đã gửi PR để chuyển đổi nó.
knowasilya

3
@ Entolering Chức năng phụ thuộc nhiệm vụ tích hợp không giải quyết được tình huống này. Nhiệm vụ phụ thuộc luôn chạy: không có xây dựng theo cách để chạy hai nhiệm vụ liên tiếp một số thời gian, nhưng không phải tất cả các thời gian. run-sequencegiải quyết một phần quan trọng của chức năng bị thiếu trong gulp.
OverZealous

2
Ngoài ra, phụ thuộc nhiệm vụ không phải là một giải pháp hoàn chỉnh. Nói rằng tôi có hai nhiệm vụ gulp độc lập chạy thử nghiệm bằng cơ sở dữ liệu. Không phụ thuộc vào người khác, nhưng tôi không muốn một trong hai chạy cùng một lúc vì cả hai đều cần sử dụng cơ sở dữ liệu.
peterjwest

3
Mô-đun tuyệt vời - Đây là một lời giải thích tuyệt vời về lý do cần thiết - blog.mdnbar.com/gulp-for-simple-build-proccess - Đây phải là câu trả lời được chấp nhận
danday74

5
Tôi rất biết ơn bạn đã thực hiện một giải pháp cho việc này, nhưng thật vô lý khi chúng ta cần thêm công cụ để có được thực hiện tuần tự. Thực hiện tuần tự phải là mặc định, hoặc ít nhất là dễ làm. Makefiles đã thực hiện tuần tự trong 40 năm. Hệ sinh thái JS làm cho tôi bị bệnh. 73 megabyte của node_modules chỉ để biên dịch dự án soạn sẵn mà không có bất kỳ tính năng nào và điều đó vẫn không bao gồm khả năng thực hiện tuần tự. Hệ điều hành phù hợp trong một không gian nhỏ hơn và chúng có KFSels và trình điều khiển FFS.
joonas.fi

371

Giải pháp tốt duy nhất cho vấn đề này có thể được tìm thấy trong tài liệu gulp có thể tìm thấy ở đây

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
Vì một số lý do, tôi đang ReferenceError: err is not definedcố gắng thực hiện điều này trong một gulp-compassnhiệm vụ, tôi có thiếu điều gì không?
waffl

11
@waffl ví dụ này sử dụng một cuộc gọi lại, đây không phải là cách duy nhất để làm điều này. Theo các tài liệu , bạn cũng có thể "trả lại một lời hứa hoặc luồng mà động cơ nên chờ để giải quyết hoặc kết thúc tương ứng." Vì vậy, nếu bạn trả về một luồng trong nhiệm vụ một, ví dụ return gulp.src('app/**/*.js').pipe(concat(app.js)).pipe(gulp.dest('app/scripts');, chìa khóa là xác định nhiệm vụ một là phụ thuộc khi xác định nhiệm vụ hai: gulp.task('two', ['one'], function() {... Nhiệm vụ hai sẽ đợi nhiệm vụ một kết thúc trước khi chạy.
esvendsen

24
Điều này tạo ra một khớp nối chặt chẽ giữa 'một' và 'hai'. Điều gì sẽ xảy ra nếu bạn muốn chạy 'hai' mà không chạy 'một'
wilk

5
bạn xác định một nhiệm vụ mới mà không phụ thuộc?
Mathieu Borderé

8
Cần hai nhiệm vụ để chạy tuần tự ngụ ý một khớp nối chặt chẽ.
Ringo

56

Tôi đã tạo một ứng dụng nút / gulp bằng trình tạo Yeoman của trình tạo-gulp-webapp . Nó xử lý "câu hỏi hóc búa" theo cách này (dịch sang các nhiệm vụ ban đầu được đề cập trong câu hỏi):

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

2
Đây là chính xác (và rất đơn giản) tôi cần. Nó giải quyết tình huống trong đó tôi cần phải làm một cái gì đó sạch sẽ như một phụ thuộc trước để xây dựng các phụ thuộc mà không đặt sạch như một phụ thuộc vào các tác vụ đó. PS: Thông tin về bit gulp.start () - caveat emptor: github.com/gulpjs/gulp/issues/426
Jaans

Điều đó có ý nghĩa; một cuộc gọi lại sau khi nhiệm vụ chính (và đó là nhiệm vụ phụ thuộc) đã hoàn thành. Cảm ơn.
markau

4
Nếu ai đó thắc mắc tại sao không có tài liệu chính thức nào gulp.start(), câu trả lời này từ thành viên gulp giải thích rằng: gulp.start is undocumented on purpose because it can lead to complicated build files and we don't want people using it(nguồn: github.com/gulpjs/gulp/issues/426#issuecomment-41208007 )
thybzi

1
Trong trường hợp này, làm thế nào tôi có thể phát hiện coffeenhiệm vụ đó đã kết thúc? Nếu tôi không phát hiện ra nó, developnhiệm vụ sẽ kết thúc sớm hơncoffee
thybzi

đã có câu trả lời từ run-sequencemã nguồn : gulp.on('task_stop'). Xem câu trả lời mở rộng của tôi để biết chi tiết: stackoverflow.com/a/38818657/3027390
thybzi

32

chuỗi chạy là cách rõ ràng nhất (ít nhất là cho đến khi Gulp 4.0 được phát hành)

Với chuỗi chạy , nhiệm vụ của bạn sẽ như thế này:

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

Nhưng nếu bạn (vì một số lý do) không thích sử dụng nó, gulp.startphương pháp sẽ giúp :

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

Lưu ý: Nếu bạn chỉ bắt đầu tác vụ mà không nghe kết quả, developtác vụ sẽ kết thúc sớm hơn coffeevà điều đó có thể gây nhầm lẫn.

Bạn cũng có thể loại bỏ trình nghe sự kiện khi không cần thiết

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

Hãy xem xét đó cũng là task_errsự kiện bạn có thể muốn nghe. task_stopđược kích hoạt khi kết thúc thành công, trong khi task_errxuất hiện khi có một số lỗi.

Bạn cũng có thể tự hỏi tại sao không có tài liệu chính thức cho gulp.start(). Câu trả lời này từ thành viên gulp giải thích những điều:

gulp.start không có giấy tờ về mục đích vì nó có thể dẫn đến các tệp xây dựng phức tạp và chúng tôi không muốn mọi người sử dụng nó

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


hai cà phê cho người đàn ông này! giải pháp với việc loại bỏ người nghe hoạt động hoàn hảo!
daniel.bavrin

Đây thực sự là câu trả lời, hoặc chỉ, "gulp 4". Trình tự chạy là mạnh mẽ.
LAdams87

26

Theo các tài liệu Gulp:

Các nhiệm vụ của bạn đang chạy trước khi các phụ thuộc hoàn thành? Đảm bảo rằng các tác vụ phụ thuộc của bạn được sử dụng chính xác bằng các gợi ý chạy async: thực hiện cuộc gọi lại hoặc trả lại lời hứa hoặc luồng sự kiện.

Để chạy chuỗi nhiệm vụ của bạn một cách đồng bộ:

  1. Trả lại luồng sự kiện (ví dụ gulp.src) gulp.taskđể thông báo cho nhiệm vụ khi luồng kết thúc.
  2. Khai báo các phụ thuộc nhiệm vụ trong đối số thứ hai của gulp.task.

Xem mã sửa đổi:

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
Đây phải là câu trả lời chính xác! Nhiệm vụ trở về đã làm mánh khóe! Cảm ơn người đàn ông.
Dzoukr

10

Tôi đã có vấn đề chính xác như vậy và giải pháp hóa ra khá dễ dàng đối với tôi. Về cơ bản thay đổi mã của bạn để sau đây và nó sẽ hoạt động. LƯU Ý: sự trở lại trước khi gulp.src tạo ra sự khác biệt cho tôi.

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"

Cảm ơn các lưu ý về việc trở lại! Đã cố gắng để tìm ra lý do tại sao gulp là nhiệm vụ src-ing không theo thứ tự.
Andrew F

Đây phải là câu trả lời chính xác để tránh khớp nối chặt chẽ giữa các nhiệm vụ. Hoạt động tốt. gulp.series có sẵn trong 4.0 có lẽ là câu trả lời tốt nhất, nhưng cho đến ngày hôm nay, 4.0 không có sẵn.
wilk

gulp Develop sẽ chạy sạch hoặc cà phê trước
scape

8

đã thử tất cả các giải pháp đề xuất, tất cả dường như có vấn đề của riêng họ.

Nếu bạn thực sự nhìn vào nguồn dàn nhạc, đặc biệt là việc .start()triển khai bạn sẽ thấy rằng nếu tham số cuối cùng là một hàm thì nó sẽ coi nó như một cuộc gọi lại.

Tôi đã viết đoạn trích này cho các nhiệm vụ của riêng tôi:

  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

Tôi đã tìm kiếm câu trả lời này trong một thời gian. Bây giờ tôi đã nhận nó trong tài liệu chính thức.

Nếu bạn muốn thực hiện một nhiệm vụ gulp khi hoàn thành nhiệm vụ cuối cùng, bạn phải trả về một luồng:

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

Đơn giản chỉ cần coffeephụ thuộc cleandevelopphụ thuộc vào coffee:

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

Công văn bây giờ là nối tiếp: cleancoffeedevelop. Lưu ý rằng cleanviệc triển khai và coffeethực hiện phải chấp nhận một cuộc gọi lại, "để động cơ biết khi nào nó sẽ được thực hiện" :

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

Tóm lại, bên dưới là mẫu gulp đơn giản cho đồng bộ cleantheo sau là phụ thuộc bản dựng không đồng bộ :

//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 đủ thông minh để chạy cleanchính xác một lần mỗi lần build, bất kể buildphụ thuộc vào bao nhiêu phụ thuộc clean. Như đã viết ở trên, cleanlà một rào cản đồng bộ hóa, sau đó tất cả các buildphụ thuộc của nó chạy song song, sau đó buildchạy.


3

Đối với tôi, nó không chạy tác vụ minify sau khi ghép vì nó mong đợi đầu vào được nối và nó không được tạo ra một số lần.

Tôi đã thử thêm vào một tác vụ mặc định theo thứ tự thực hiện và nó không hoạt động. Nó hoạt động sau khi thêm chỉ một returncho mỗi nhiệm vụ và nhận được sự thu nhỏ bên trong gulp.start()như bên dưới.

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

Nguồn http://schickling.me/synyncous-t task-gulp /


2

Gulp và Node sử dụng lời hứa .

Vì vậy, bạn có thể làm điều này:

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

Nếu bạn trả về luồng gulp, bạn có thể sử dụng then()phương thức để thêm một cuộc gọi lại. Thay phiên, bạn có thể sử dụng nguồn gốc của Node Promiseđể tạo lời hứa của riêng bạn. Ở đây tôi sử dụng Promise.all()để có một cuộc gọi lại kích hoạt khi tất cả các lời hứa được giải quyết.


-8

Hãy thử bản hack này :-) Gulp v3.x Hack vì lỗi Async

Tôi đã thử tất cả các cách "chính thức" trong Readme, chúng không hiệu quả với tôi nhưng điều này đã làm. Bạn cũng có thể nâng cấp lên gulp 4.x nhưng tôi thực sự khuyên bạn không nên, nó phá vỡ quá nhiều thứ. Bạn có thể sử dụng một lời hứa js thực sự, nhưng này, nó nhanh, bẩn, đơn giản :-) Về cơ bản bạn sử dụng:

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

Kiểm tra bài!


Có nhiều cách tốt hơn để giải quyết vấn đề, sử dụng setTimeout không được chiếm dụng. Bạn không thể biết chính xác thời gian một nhiệm vụ sẽ hoàn thành.
Reginaldo Camargo Ribeiro

Bạn thực sự nên suy nghĩ trước khi viết bất kỳ mã pff nào
DDD
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.