266

I have the following gulpfile.js, which I'm executing via the command line gulp message:

var gulp = require('gulp');

gulp.task('message', function() {
  console.log("HTTP Server Started");
});

I'm getting the following error message:

[14:14:41] Using gulpfile ~\Documents\node\first\gulpfile.js
[14:14:41] Starting 'message'...
HTTP Server Started
[14:14:41] The following tasks did not complete: message
[14:14:41] Did you forget to signal async completion?

I'm using gulp 4 on a Windows 10 system. Here is the output from gulp --version:

[14:15:15] CLI version 0.4.0
[14:15:15] Local version 4.0.0-alpha.2
simhumileco
  • 21,911
  • 14
  • 106
  • 90
John Deighan
  • 3,502
  • 4
  • 14
  • 15
  • 1
    If you're here because you've got an issue with `webpack-stream`. Use this: https://github.com/shama/webpack-stream/issues/34#issuecomment-478602446 – B3none Apr 01 '19 at 15:53

16 Answers16

526

Since your task might contain asynchronous code you have to signal gulp when your task has finished executing (= "async completion").

In Gulp 3.x you could get away without doing this. If you didn't explicitly signal async completion gulp would just assume that your task is synchronous and that it is finished as soon as your task function returns. Gulp 4.x is stricter in this regard. You have to explicitly signal task completion.

You can do that in six ways:

1. Return a Stream

This is not really an option if you're only trying to print something, but it's probably the most frequently used async completion mechanism since you're usually working with gulp streams. Here's a (rather contrived) example demonstrating it for your use case:

var print = require('gulp-print');

gulp.task('message', function() {
  return gulp.src('package.json')
    .pipe(print(function() { return 'HTTP Server Started'; }));
});

The important part here is the return statement. If you don't return the stream, gulp can't determine when the stream has finished.

2. Return a Promise

This is a much more fitting mechanism for your use case. Note that most of the time you won't have to create the Promise object yourself, it will usually be provided by a package (e.g. the frequently used del package returns a Promise).

gulp.task('message', function() { 
  return new Promise(function(resolve, reject) {
    console.log("HTTP Server Started");
    resolve();
  });
});

Using async/await syntax this can be simplified even further. All functions marked async implicitly return a Promise so the following works too (if your node.js version supports it):

gulp.task('message', async function() {
  console.log("HTTP Server Started");
});

3. Call the callback function

This is probably the easiest way for your use case: gulp automatically passes a callback function to your task as its first argument. Just call that function when you're done:

gulp.task('message', function(done) {
  console.log("HTTP Server Started");
  done();
});

4. Return a child process

This is mostly useful if you have to invoke a command line tool directly because there's no node.js wrapper available. It works for your use case but obviously I wouldn't recommend it (especially since it's not very portable):

var spawn = require('child_process').spawn;

gulp.task('message', function() {
  return spawn('echo', ['HTTP', 'Server', 'Started'], { stdio: 'inherit' });
});

5. Return a RxJS Observable.

I've never used this mechanism, but if you're using RxJS it might be useful. It's kind of overkill if you just want to print something:

var of = require('rxjs').of;

gulp.task('message', function() {
  var o = of('HTTP Server Started');
  o.subscribe(function(msg) { console.log(msg); });
  return o;
});

6. Return an EventEmitter

Like the previous one I'm including this for completeness sake, but it's not really something you're going to use unless you're already using an EventEmitter for some reason.

gulp.task('message3', function() {
  var e = new EventEmitter();
  e.on('msg', function(msg) { console.log(msg); });
  setTimeout(() => { e.emit('msg', 'HTTP Server Started'); e.emit('finish'); });
  return e;
});
Sven Schoenung
  • 27,914
  • 8
  • 57
  • 63
  • 7
    After a couple of hours of googling, I found this example. Very helpful. Thank you! – paxtor Jul 11 '16 at 15:45
  • it‘s helpful for me,ths! – Anan Aug 09 '16 at 09:03
  • 2
    I so appreciate your answer. +1 big time. – Konrad Viltersten Nov 17 '16 at 09:59
  • 9
    I appreciated your elegant and informative answer on November the 17th. And today, on Christmas day, I'm appreciating it all over again. This is one of the cases when I wish I could award +2... I can't believe that goolearching doesn't poops out this link as top #1 when looking for "*The following tasks did not complete*" or "*Did you forget to signal async completion?*"... – Konrad Viltersten Dec 24 '16 at 23:06
  • "the frequently used del package returns a Promise". I'm using del, how do I write my gulp code to take advantage of the promise though? (PS. Absolutely amazing answer! +1) – Daniel Tonon Feb 05 '17 at 11:18
  • @DanielTonon Just return the Promise from your task. [See this answer](http://stackoverflow.com/a/32613701/5892036). – Sven Schoenung Feb 05 '17 at 11:29
  • https://gist.github.com/demisx/beef93591edc1521330a#file-gulpfile-js-L215 I've seen a few example Gulp 4 examples such as this one where watchers don't seem to be accompanied by completion signals. What is signaling async completion here? Is there something unique about gulp.watch() or should he be using one of the methods you listed? – Corey May 11 '17 at 21:38
  • @KonradViltersten it's #1 in a Google search now! Thanks for the answer sven! – John R Perry Jun 20 '18 at 18:56
  • Adding another related to Gulp 4, for those who come by: [https://stackoverflow.com/a/32704073/3676036](https://stackoverflow.com/a/32704073/3676036) – SJL Sep 22 '18 at 06:10
  • Could you take a look at this question https://stackoverflow.com/questions/53360791/how-to-change-gulp-default-task-timeout ? – Pavel_K Nov 18 '18 at 12:23
  • Ad 3. Call the callback function: when you have to wait for a pipe to finish, the correct way to write this would be `.pipe(...).on('finish', done)` (or 'end' depending on your pipe) – fabb Dec 07 '18 at 14:53
  • I'm pull my hair out with this as even "returning a stream" isn't working. – jgmjgm Mar 13 '19 at 10:56
  • @SvenSchoenung - I love you man. And by that I mean brotherly love. You saved me. – Greeso Mar 26 '19 at 20:39
  • This was an exemplary solution. Thank you so much! – producerism Jun 17 '19 at 21:28
  • Thanks so much for this detailed explanation! Very helpful! – claytonjwong Feb 28 '20 at 16:54
  • The `async function()` is the quickest, simplest solution.. Well done +1 ! – Hasan Alsawadi Sep 20 '20 at 10:50
117

An issue with Gulp 4.

For solving this problem try to change your current code:

gulp.task('simpleTaskName', function() {
  // code...
});

for example into this:

gulp.task('simpleTaskName', async function() {
  // code...
});

or into this:

gulp.task('simpleTaskName', done => {
  // code...
  done();
});
simhumileco
  • 21,911
  • 14
  • 106
  • 90
23

This worked!

gulp.task('script', done => {
    // ... code gulp.src( ... )
    done();
});

gulp.task('css', done => {
    // ... code gulp.src( ... )
    done();
});

gulp.task('default', gulp.parallel(
        'script',
        'css'
  )
);

Last updated on Feb 18, 2021, I found the problem after using the above solution then I have fixed it by using the following instead for the following gulp version.

File: Package.json

...,
"devDependencies": {
        "del": "^6.0.0",
        "gulp": "^4.0.2",
      },
...

File: gulpfile.js Example

const {task} = require('gulp');
const del = require('del');

async function clean() {
    console.log('processing ... clean');

    return del([__dirname + '/dist']);
}

task(clean)
...
Khachornchit Songsaen
  • 1,778
  • 18
  • 15
13

I was getting this same error trying to run a very simple SASS/CSS build.

My solution (which may solve this same or similar errors) was simply to add done as a parameter in the default task function, and to call it at the end of the default task:

// Sass configuration
var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('sass', function () {
    gulp.src('*.scss')
        .pipe(sass())
        .pipe(gulp.dest(function (f) {
            return f.base;
        }))
});

gulp.task('clean', function() {
})

gulp.task('watch', function() {
    gulp.watch('*.scss', ['sass']);
})


gulp.task('default', function(done) { // <--- Insert `done` as a parameter here...
    gulp.series('clean','sass', 'watch')
    done(); // <--- ...and call it here.
})

Hope this helps!

simhumileco
  • 21,911
  • 14
  • 106
  • 90
KLPA
  • 189
  • 1
  • 3
  • 7
    Nice to see an example with actual task contents – Jonathan May 27 '19 at 22:46
  • This doesn't look like it would wait for the series of tasks to finish, if you're calling done() immediately after gulp.series(). Maybe the process waits before exiting, but it seems this wouldn't work well if you try to compose it into a larger structure of tasks. – 1j01 Jan 26 '21 at 05:23
11

This is an issue when migrating from gulp version 3 to 4, Simply you can add a parameter done to the call back function , see example,

   const gulp = require("gulp")

    gulp.task("message", function(done) {
      console.log("Gulp is running...")
      done()
    });
Moftah
  • 141
  • 1
  • 3
11

You need to do one thing:

  • Add async before function.

const gulp = require('gulp');

gulp.task('message', async function() {
    console.log("Gulp is running...");
});
8

I cannot claim to be very knowledgeable on this but I had the same problem and have resolved it.

There is a 7th way to resolve this, by using an async function.

Write your function but add the prefix async.

By doing this Gulp wraps the function in a promise, and the task will run without errors.

Example:

async function() {
  // do something
};

Resources:

  1. Last section on the Gulp page Async Completion: Using async/await.

  2. Mozilla async functions docs.

simhumileco
  • 21,911
  • 14
  • 106
  • 90
Jonny
  • 593
  • 4
  • 15
8

You need to do two things:

  1. Add async before function.
  2. Start your function with return.

    var gulp = require('gulp');
    
    gulp.task('message', async function() {
        return console.log("HTTP Server Started");
    });
    
simhumileco
  • 21,911
  • 14
  • 106
  • 90
Majali
  • 362
  • 3
  • 8
7

Workaround: We need to call the callback functions (Task and Anonymous):

function electronTask(callbackA)
{
    return gulp.series(myFirstTask, mySeccondTask, (callbackB) =>
    {
        callbackA();
        callbackB();
    })();    
}
simhumileco
  • 21,911
  • 14
  • 106
  • 90
5

Basically v3.X was simpler but v4.x is strict in these means of synchronous & asynchronous tasks.

The async/await is pretty simple & helpful way to understand the workflow & issue.

Use this simple approach

const gulp = require('gulp')

gulp.task('message',async function(){
return console.log('Gulp is running...')
})
4

Here you go: No synchronous tasks.

No synchronous tasks

Synchronous tasks are no longer supported. They often led to subtle mistakes that were hard to debug, like forgetting to return your streams from a task.

When you see the Did you forget to signal async completion? warning, none of the techniques mentioned above were used. You'll need to use the error-first callback or return a stream, promise, event emitter, child process, or observable to resolve the issue.

Using async/await

When not using any of the previous options, you can define your task as an async function, which wraps your task in a promise. This allows you to work with promises synchronously using await and use other synchronous code.

const fs = require('fs');

async function asyncAwaitTask() {
  const { version } = fs.readFileSync('package.json');
  console.log(version);
  await Promise.resolve('some result');
}

exports.default = asyncAwaitTask;
simhumileco
  • 21,911
  • 14
  • 106
  • 90
3

My solution: put everything with async and await gulp.

async function min_css() {
    return await gulp
        .src(cssFiles, { base: "." })
        .pipe(concat(cssOutput))
        .pipe(cssmin())
        .pipe(gulp.dest("."));
}

async function min_js() {
    return await gulp
        .src(jsFiles, { base: "." })
        .pipe(concat(jsOutput))
        .pipe(uglify())
        .pipe(gulp.dest("."));  
}

const min = async () => await gulp.series(min_css, min_js);

exports.min = min;

Kat Lim Ruiz
  • 1,993
  • 1
  • 21
  • 28
1

I was struggling with this recently, and found the right way to create a default task that runs sass then sass:watch was:

gulp.task('default', gulp.series('sass', 'sass:watch'));
0

Add done as a parameter in default function. That will do.

bmayur
  • 21
0

For those who are trying to use gulp for swagger local deployment, following code will help

var gulp = require("gulp");
var yaml = require("js-yaml");
var path = require("path");
var fs = require("fs");

//Converts yaml to json
gulp.task("swagger", done => {
    var doc = yaml.safeLoad(fs.readFileSync(path.join(__dirname,"api/swagger/swagger.yaml")));
    fs.writeFileSync(
        path.join(__dirname,"../yourjsonfile.json"),
        JSON.stringify(doc, null, " ")
        );
    done();
});

//Watches for changes    
gulp.task('watch', function() {
  gulp.watch('api/swagger/swagger.yaml', gulp.series('swagger'));  
});
hellowahab
  • 2,174
  • 4
  • 16
  • 31
0

For me the issue was different: Angular-cli was not installed (I installed a new Node version using NVM and simply forgot to reinstall angular cli)

You can check running "ng version".

If you don't have it just run "npm install -g @angular/cli"

Ari Waisberg
  • 909
  • 1
  • 9
  • 20