Rusty Shackleford
Rusty Shackleford

Reputation: 1141

Gulp 4: How to use gulp.series() and gulp.parallel() inside a function?

I want to define a Gulp 4 task that is a composition of three functions executed in series. However, I want to define it as a named function rather than using gulp.task():

function beforeTest() { ... }
function coreTest() { ... }
function afterTest() { ... }

export function test() {
    // what goes here?
    // this function should be equivalent to:
    // gulp.task('test', gulp.series(beforeTest, coreTest, afterTest));
}

I found a similar question asked on the Gulp GitHub issue tracker where the OP tried the equivalent of the following:

export function test() {
    return gulp.series(beforeTest, coreTest, afterTest);
}

The reason why this does not work is explained in the GitHub issue. The recommended solution from the Gulp team was to not use a named function but to rather assign the composite function to a variable:

export const test = gulp.series(beforeTest, coreTest, afterTest);

However, this solution appears deficient for a few reasons.

The first deficiency was raised in a comment on the GitHub issue about the restriction this places on task ordering (something I was already trying to avoid by using named functions instead of gulp.task() due to the new requirement in Gulp 4 that task names must be registered before they are referenced).

The second deficiency is more cosmetic (and thus triggers my OCD :-) ). When running gulp test, the composite test task is displayed in the output:

[00:00:00] Starting 'test'...
[00:00:00] Starting 'beforeTest'...
[00:00:00] Finished 'beforeTest' after 106 ms
[00:00:00] Starting 'coreTest'...
[00:00:00] Finished 'coreTest' after 214 ms
[00:00:00] Starting 'afterTest'...
[00:00:00] Finished 'afterTest' after 280 μs
[00:00:00] Finished 'test' after 324 ms

However, if I have another composite task that references test, such as:

gulp.task('build', gulp.parallel(lint, test));

Then when I run gulp build, the composite test task is not displayed in the output:

[00:00:00] Starting 'build'...
[00:00:00] Starting 'lint'...
[00:00:00] Starting 'beforeTest'...
[00:00:01] Finished 'beforeTest' after 1.08 s
[00:00:01] Starting 'coreTest'...
[00:00:02] Finished 'coreTest' after 977 ms
[00:00:02] Starting 'afterTest'...
[00:00:02] Finished 'afterTest' after 232 μs
[00:00:07] Finished 'lint' after 6.96 s
[00:00:07] Finished 'build' after 6.96 s

I suspect this may be because Gulp does not display any function whose name is series or parallel. I tried setting test.displayName, as suggested in the GitHub issue:

export const test = gulp.series(beforeTest, coreTest, afterTest);
test.displayName = 'test';

But that didn't change the output of gulp build. I also tried setting test.name, but that property appears to be frozen:

TypeError: Cannot assign to read only property 'name' of function 'function series(done) {
    nowAndLater.mapSeries(args, asyncDone, extensions, done);
  }'

It seems that if I could define the composite test task as a named function, it would address both of these deficiencies. So, in summary, how would I define the body of the test function shown at the top of this question?

Upvotes: 3

Views: 4179

Answers (1)

Rusty Shackleford
Rusty Shackleford

Reputation: 1141

export function test(...args) {
    return gulp.series(beforeTest, coreTest, afterTest)(...args);
}

The function arguments must be passed through to the composite function returned by gulp.series() in the event any component function requires the Gulp task callback parameter (i.e. cb, done, whatever).

This task definition produces the desired output when running gulp build:

[00:00:00] Starting 'build'...
[00:00:00] Starting 'lint'...
[00:00:00] Starting 'test'...
[00:00:00] Starting 'beforeTest'...
[00:00:01] Finished 'beforeTest' after 1.06 s
[00:00:01] Starting 'coreTest'...
[00:00:02] Finished 'coreTest' after 949 ms
[00:00:02] Starting 'afterTest'...
[00:00:02] Finished 'afterTest' after 302 μs
[00:00:02] Finished 'test' after 2.05 s
[00:00:07] Finished 'lint' after 7.12 s
[00:00:07] Finished 'build' after 7.12 s

EDIT: A deficiency of this solution is that by deferring the call to gulp.series() until the test task is actually executed, the child tasks do not show up in the task map displayed by gulp --tasks.

For example, using the proposed solution, the output of gulp --tasks is

[00:00:00] Tasks for ~/gulpfile.babel.js
[00:00:00] └── test

Whereas, defining test as a variable as suggested in the original GitHub issue, the output is

[00:00:00] Tasks for ~/gulpfile.babel.js
[00:00:00] └─┬ test
[00:00:00]   └─┬ <series>
[00:00:00]     ├── beforeTest
[00:00:00]     ├── coreTest
[00:00:00]     └── afterTest

This isn't an issue for the question posed because the beforeTest, coreTest, and afterTest functions are not actual tasks (i.e. they are not exported), so I actually do not want them to show up. But, because I can easily see getting into the same situation with exported subtasks, I don't feel this solution is completely intellectually satisfying.

Upvotes: 3

Related Questions