こんにちは。フロントエンドエンジニアのhikaruです。
直近担当しているリニューアル案件で、過去に作った gulpfile を修正している際に、
ついでに gulp v4 にアップデートしてみよー!
という軽い気持ちでろくに下調べもせずにアップデートしてみたところ、タスクの記述方法の修正が必要だったので、アップデートを考えている方のお役に立てばと思い、遭遇したエラーと対処方法をまとめてみました。
- gulpfile 修正しなきゃいけないの…?
- 他のプロジェクトで使ってる gulp のバージョンに影響ないの…?
と思った方もご安心ください(๑•̀ㅂ•́)و✧
他のプロジェクトに影響を与えない & これだけ修正すれば大丈夫!というポイントをお伝えします。
まずは結論から
修正が必要なのは以下3点のみです。
- gulp.task の引数の変更
- gulp.watch の引数の変更
- ローカルの gulp を参照するようにする
1. gulp.task の引数の変更
ローカルに gulp v4 をインストールしてそのまま gulp
を実行すると、以下のエラーが出ます。
assert.js:351 throw err; ^ AssertionError [ERR_ASSERTION]: Task function must be specified at Gulp.set [as _setTask] (/project/node_modules/undertaker/lib/set-task.js:10:3) at Gulp.task (/project/node_modules/undertaker/lib/task.js:13:8) ...
これは gulp.task
の引数が 3つから 2つに変更されたため起こるエラーです。
- v3:gulp.task(name [, deps] [, fn])
- v4:gulp.task([name,] fn)
依存関係のあるタスクは、gulp v4 で追加された API を使って指定します。
- gulp.series:タスクを直列処理する
- gulp.parallel:タスクを並列処理する
Gulp Documentation -gulp.series
たとえば、一度ディレクトリを削除してからビルドを実行したい場合、次のように書き換えます。
gulp v3
gulp.task('sass', ['clean'], function() { ... }); gulp.task('js', ['clean'], function() { ... }); gulp.task('build', ['sass', 'js']);
gulp v4
gulp.task('build', gulp.series('clean', // 直列処理 gulp.parallel('sass', 'js') // 並列処理 ));
今までは個別のタスクの引数に依存関係を指定したり、run-sequence などのプラグインを使用する必要がありましたが、標準の API でより直感的に記述できるようになりました。
2. gulp.watch の引数の変更
gulp.watch
の引数も以下のように変更されました。
- v3:gulp.task(glob [, opts], tasks)
- v4:gulp.task(glob [, opts] [, fn])
Gulp Documentation -gulp.watch
次のように書き換えます。
gulp v3
gulp.watch('src/sass/**/*.scss', ['sass']);
gulp v4
gulp.watch('src/sass/**/*.scss', gulp.task('sass'));
第二引数には gulp.task
, gulp.series
, gulp.parallel
の他、関数名や無名関数をそのまま記述しても大丈夫です。
3. ローカルの gulp を参照するようにする
ここまで修正して gulp
を実行すると、以下のエラーが出ます。
gulpInst.start.apply(gulpInst, toRun); ^ TypeError: Cannot read property 'apply' of undefined at /usr/local/lib/node_modules/gulp/bin/gulp.js:129:20 at internalTickCallback (internal/process/next_tick.js:70:11) ...
グローバルとローカルのバージョンが違うことで出るエラーのようです。
現状 ↓
[14:57:20] CLI version 3.9.1 [14:57:20] Local version 4.0.0
他のプロジェクトの gulpfile も修正が必要になっちゃうなー… どうしたものか… と思い調べていたら、ローカルの gulp を参照する方法がありました(`・ω・´)
package.json に 以下のように定義することで npm run gulp
で実行できるようになります。
"scripts": { "gulp": "gulp" }
gulp 公式の導入手順にもグローバルにインストールするようかかれていますが、アップデートの際に他のプロジェクトや環境でのバージョンの違いを考慮する必要があるため、プロジェクト内の node_modules だけで完結させられたほうが便利ですね。
補足1:npm scripts の登録
- 個別のタスクを実行したいときに、いつもの感じで
gulp taskname
とコマンドをたたくと、グローバルが参照され上記の TypeError が出てしまうので、デフォルト以外に個別で使うことがあるタスクは npm scripts として設定してnpm run taskname
で実行できるようにしたほうがよいでしょう。 - 登録したタスク一覧は
npm run
で見ることができます。
わたしはこんな感じで設定しました。
package.json
"scripts": { "gulp": "gulp", // よく使うタスク "watch": "gulp", "dev": "gulp build --development", "prod": "gulp build --production", // たまに個別で使うタスク "sass": "gulp sass", "js": "gulp js", "copy": "gulp copy", "image": "gulp image", "ejs": "gulp ejs" },
補足2:タスクの終了を明示的にする
1〜3 まで修正して npm run gulp
を実行したところ、こんなエラーがでました。
[15:14:22] 'default' errored after 14 ms [15:14:22] The following tasks did notcomplete: server [15:14:22] Did you forget to signal async completion?
gulp v4 では、タスクの終了を明示的にしないと、タスクが完了せずにそこでエラーとなるようになりました。
タスクが1つであれば、今まで通り return をしてストリームを返すようにすれば解決します。
gulp.task('somename', function() { return gulp.src('client/**/*.js') .pipe(minify()) .pipe(gulp.dest('build')); });
タスクの終了を gulp に明示的に伝えるためには以下の 5つの方法があるようです。
- 最後に callback を実行する
- streamを返す
- promiseを返す
- child processを返す
- RxJS observableを返す
Gulp Documentation -Async support
公式ドキュメントにサンプルコード付きで解説されています。
まとめ
今回はパパっとアップデートすることが目的だったので、最低限対応が必要なことのみまとめました。
他にも
gulp.tree
メソッドの追加gulp.registry
メソッドの追加gulp.src
やgulp.dest
のオプションの追加- タスクの定義を
gulp.task
ではなく JavaScript で関数を定義するように記述できるようになった
などさまざまな変更点があるので、気になる方は 公式のAPIドキュメント を見てみてください。
gulp.task
と gulp.watch
の書き方を見直せば問題なく移行できるので、gulp v4 への移行はそれほど大変じゃない!というお話でした。
\\『明日のはたらくを創る』仲間を募集中!! // 919.jp