gulp3→4の変更点に気をつけよう

これは[ユアマイスター Advent Calendar 2018](https://qiita.com/advent-calendar/2018/yourmystar)の23日目の記事です。

`AssertionError: Task function must be specified`に長らくお世話になりましたので、こちらに関する内容を記載したいと思います。

##引数指定の変更

4系から*gulp.task*や*gulp.watch*の第二引数の指定方法が変わっています。

**gulp.task**の場合

```js
// 3系の場合
gulp.task('default', ['sass']);
```

```js
// 4系の場合
gulp.task('default', gulp.task('sass'));
```

**gulp.watch**の場合

```js
// 3系の場合
gulp.watch('webroot/sass/*.sass', ['sass']);
```

```js
// 4系の場合
gulp.watch('webroot/sass/*.sass', gulp.task('sass'));
```

配列指定から、関数指定になるイメージですかね。
この変更をしていないと、自分のように`AssertionError: Task function must be specified`と長い間お付き合いする事になります。

##gulp.seriesの解説

*gulp.series*は4系で追加された関数で、順番に実行するというものです。

```js:Gulpfile.js
gulp.task('one', function(done) {
    console.log('task one');
    done();
});

gulp.task('two', function(done) {
    console.log('task two');
    done();
});

gulp.task('default', gulp.series('one', 'two', function(done) {
    console.log('task default');
    done();
}));
```

サンプルコードです。
*gulp.series*には`task('one', ...)`と`task('two', ...)`を指定しています。
これを**gulp**で実行すると

```
[vagrant@local hoge]$ gulp
[02:47:42] Using gulpfile /vagrant/sample/gulpfile.js
[02:47:42] Starting 'default'...
[02:47:42] Starting 'one'...
task one
[02:47:42] Finished 'one' after 880 μs
[02:47:42] Starting 'two'...
task two
[02:47:42] Finished 'two' after 330 μs
[02:47:42] Starting '<anonymous>'...
task default
[02:47:42] Finished '<anonymous>' after 169 μs
[02:47:42] Finished 'default' after 5.52 ms
[vagrant@local hoge]$ 
```

順番に実行されていることがわかります。
一応*gulp.series*の`one`と`two`を逆にして実行してみます。

```
[vagrant@local hoge]$ gulp
[02:50:05] Using gulpfile /vagrant/sample/gulpfile.js
[02:50:05] Starting 'default'...
[02:50:05] Starting 'two'...
task two
[02:50:05] Finished 'two' after 1.56 ms
[02:50:05] Starting 'one'...
task one
[02:50:05] Finished 'one' after 244 μs
[02:50:05] Starting '<anonymous>'...
task default
[02:50:05] Finished '<anonymous>' after 217 μs
[02:50:05] Finished 'default' after 4.55 ms
[vagrant@local hoge]$ 
```

想定通り順番に実行されている事がわかりました。

##gulp.parallelの解説

*gulp.parallel*は4系で追加された関数で、並列で実行するというものです。
上記サンプルコードの`gulp.series`部分を`gulp.parallel`に変えて実行してみます。

```js:Gulpfile.js
gulp.task('one', function(done) {
    console.log('task one');
    done();
});

gulp.task('two', function(done) {
    console.log('task two');
    done();
});

gulp.task('default', gulp.parallel('one', 'two', function(done) {
    console.log('task default');
    done();
}));
```

実行結果

```
[vagrant@local hoge]$ gulp
[03:21:41] Using gulpfile /vagrant/sample/gulpfile.js
[03:21:41] Starting 'default'...
[03:21:41] Starting 'one'...
[03:21:41] Starting 'two'...
[03:21:41] Starting '<anonymous>'...
task one
[03:21:41] Finished 'one' after 1.63 ms
task two
[03:21:41] Finished 'two' after 1.52 ms
task default
[03:21:41] Finished '<anonymous>' after 1.56 ms
[03:21:41] Finished 'default' after 4.22 ms
[vagrant@local hoge]$ 
```

`Starting`に注目して下さい。
**one**と**two**が平行して実行されている事がわかります。
`gulp.parallel`に指定された*task*はこのように平行して実行されます。

###callbackについて
各*task*の*function*の引数に`done`が指定されていて、*function*内の処理で`done();`が実行されています。
これは*callback*といって、*task*内の処理の終了を意味します。
なので、このメソッドが呼ばれたタイミングで、その*task*の処理は終了を宣言します。

`gulp.task('default', ..., function(done){...})`内の`done();`外して実行してみます。

```
[vagrant@local hoge]$ gulp
[03:12:04] Using gulpfile /vagrant/sample/gulpfile.js
[03:12:04] Starting 'default'...
[03:12:04] Starting 'one'...
task one
[03:12:04] Finished 'one' after 985 μs
[03:12:04] Starting 'two'...
task two
[03:12:04] Finished 'two' after 465 μs
[03:12:04] Starting '<anonymous>'...
task default
[03:12:04] The following tasks did not complete: default, <anonymous>
[03:12:04] Did you forget to signal async completion?
[vagrant@local hoge]$ 
```

このように*task default*の`Starting`はありますが、*callback*していない事によって`Finished`が走りません。

その為、`Did you forget to signal async completion?`というエラーが表示されます。

つまり、各*task*では処理実行の終了を宣言する必要があります。

##参考
https://zzz.buzz/2016/11/19/gulp-4-0-upgrade-guide/
https://github.com/gulpjs/gulp
https://gist.github.com/jeromecoupe/0b807b0c1050647eb340360902c3203a