Search code examples
gulpgulp-watchgulp-4

Signal async completion error although I returned a stream


I can't figure out why I'm getting

Did you forget to signal async completion?

Here's my setup:

gulp.task('compile-ts', () => {
    return tsProject.src(config.files.src.ts)
        .pipe($.tap((file, t) => {
            logVerbose('Compiling "' + file.path + "'");
        }))
        .pipe($.sourcemaps.init())
        .pipe($.typescript(tsProject))
        .pipe($.sourcemaps.write('./'))
        .pipe($.chmod(755))
        .pipe(gulp.dest(config.dist));
});

gulp.task('copy-assets', () => {
    return gulp.src(config.files.src.css_html_js, { base: config.src })
        .pipe($.tap((file, t) => {
            logVerbose('Copying "' + getFileName(file.path) + "'");
        }))
        .pipe($.chmod(755))
        .pipe(gulp.dest(config.dist));
});

gulp.task('browser-sync', (done) => {
    browserSync.init({
        "port": 3000,
        "startPath": "dist/index.html",
        "browser": "chrome",
        "logLevel": "silent",
        "server": {
            "middleware": {
                "0": null
            }
        }
    }, done);  
    process.on('exit', () => {
        browserSync.exit();
    });
})

gulp.task('watch', gulp.parallel(() => {
    gulp.watch(config.files.ts, gulp.series('compile-ts'));
}, () => {
    gulp.watch(config.files.css_html_js, gulp.series('copy-assets'));
}));

gulp.task('serve-dist', gulp.parallel('watch', 'browser-sync'));

According to the stacktrace, the offending line is

gulp.watch(config.files.ts, gulp.series('compile-ts'));

inside the watch task. The task compile-ts is working and it returns a stream, which should be enough to signal completion. But why am I getting the error anyway?

This is [email protected].

EDIT:

Changing the watch task to

gulp.task('watch', (done) => {
    gulp.watch(config.files.css_html_js, gulp.series('copy-assets'));
    gulp.watch(config.files.ts, gulp.series('compile-ts'));
    done();
});

I don't get any errors anymore, but the task is finished within 4ms and does nothing at all. If I remove the done part, I get the same error again.

EDIT2: I split the tasks up some more to be able to pinpoint the problem,

gulp.task('watch-ts', () => {
    return gulp.watch(config.files.ts, gulp.series('compile-ts'));
});

gulp.task('watch-assets', () => {
    return gulp.watch(config.files.css_html_js, gulp.series('copy-assets'));
});

gulp.task('watch', gulp.parallel('watch-ts', 'watch-assets'));

Now watch-ts and watch-assets both give me that error message. Either of which returns a stream as far as I can tell.


Solution

  • You always need to signal async completion in every function that composes a task. Not just those that are asynchrounous. Not just those that use streams. If you're not returning a stream in a function, you still need to signal async completion somehow (usually by invoking a callback).

    So your first edit was already correct:

    gulp.task('watch', (done) => {
      gulp.watch(config.files.css_html_js, gulp.series('copy-assets'));
      gulp.watch(config.files.ts, gulp.series('compile-ts'));
      done();
    });
    

    Invoking the callback here makes sure that gulp knows that your watch task has completed successfully. "Completed successfully" in this case means that your task has started the two watches. Both watches will continue to run even after the watch job has finished. So there's nothing wrong with the fact that the watch task terminates after 4ms.

    Starting a watch however does not automatically trigger the execution of the listener function. You'll have to modify one of the watched files first. Alternatively you can pass the ignoreInitial option to gulp.watch() which will trigger the watch when it first starts up:

    gulp.task('watch', (done) => {
      gulp.watch(config.files.css_html_js, {ignoreInitial:false}, gulp.series('copy-assets'));
      gulp.watch(config.files.ts, {ignoreInitial:false}, gulp.series('compile-ts'));
      done();
    });