168
134

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

帰ってきたGulp 4

Last updated at Posted at 2018-02-26

2014年あたりから、v4が出なくてやきもきしていましたが、待つこと3年(4年?)、2018年のはじめにv4.0.0リリースされました。2018年現在の視点で、v4をチェックしてみたいと思います。

タスクは関数に

以下、GitHubにある例からの抜粋です。(多少変形しています)

import {src, dest} from 'gulp'
import less from 'gulp-less'
import rename from 'gulp-rename'
import cleanCSS from 'gulp-clean-css'

export default () => src('src/style.css')
  .pipe(less())
  .pipe(cleanCSS())
  .pipe(rename({basename: 'main', suffix: '.min'}))
  .pipe(dest('somewhere/'))

今までgulp.task('default', function () {...})とやっていた部分が、ただの関数をエクスポートする形になります。

メモ: 後方互換も維持されていて、gulp.task()も引き続き使えます。

JavaScriptの作法でエクスポート

複数のタスクがある場合は、それぞれをエクスポートする形です。seriesparallelで、順番に実行したり並行実行を指定できます。

import {src, dest, series} from 'gulp'

export const styles = () => src(...).pipe(...) // 略
export const scripts = () => src(...).pipe(...) // 略
export default series(styles, scripts)

以前よりJavaScriptの文法に沿った書き方ができる分、だいぶ読みやすい!

タスクの中でgulpを使わなくてもいい

v3でもそうでしたが、Promiseを返すものなら何でもOKです。v4になって、というよりもasync/awaitが使えるようになって、だいぶ書きやすさが増しました。

import {src, dest} from 'gulp'
import del from 'del'

export const clean = () => del(['assets'])
export const someAsyncFunc = async () => {...} // 略
export const other = () => src(...).pipe(...) // 略

インストール

インストールに際して、

$ npm install --save-dev gulp

だと、まだv3系がインストールされます。代わりに次のようにします。

$ npm install --save-dev gulp@next

CLIを使う

CLIの使い方はあまり変化ありませんが、npm@5.2.0から、npxコマンドが追加されたので、次のような呼び出しが可能です。

$ npx gulp

グローバルにgulp-cliを入れなくて済みます。

メモ: gulp-cliは、gulpの依存性として、ローカルのnode_modulesにインストールされています。

なお、上述の例のようにimport/exportを使う場合、Nodeのネイティブ対応はまだなので、トランスパイルの必要があります。GitHubのドキュメントにbabelを使う方法が書かれていますので、そちらをどうぞ。

あるいは、babelが大げさに感じるならreifyでも動きました。

$ npm install --save-dev reify
$ npx gulp --require reify

CLIを使わない

gulp.task()の呪縛から離れたので、gulpのスクリプトを直接「プログラマブルに」扱いたいケースは増えそうです。

// build.js
import {src, dest, series} from 'gulp'

const styles = src(...).pipe(...) // 略
const scripts = src(...).pipe(...) // 略
const build = series(styles, scripts)

build()

上記の例は、node build.jsすれば動きます。(実際には、babelかreifyが必要)

なお、gulpのタスクは基本的にはストリームなので、async/awaitでは直接扱えません。gulp.seriesgulp.parallelで制御するのが良いでしょう。どうしても使いたい場合はstream-to-promiseあたりで、Promiseの文脈に持ち込む手はあります。

// build2.js
import {src, dest} from 'gulp'
import toPromise from 'stream-to-promise'

const styles = src(...).pipe(...) // 略
const scripts = src(...).pipe(...) // 略

const main = async () => {
  await toPromise(styles)
  await toPromise(scripts)
}
main()

メモ: gulp.start()はディスコンになりました。

まとめ

gulp4になって、次の点が寄与してboilerplateから完全に解放されました。:tada:

  • タスクがただの関数になったこと
  • ES2015の文法

素のNodeのスクリプトを書くのともう変わらないので、タスクランナー嫌い(?)のひとも、改めてチェックしてみても良いかも。

雑感

gulpの最大の利点は(今も昔も)次の2点です。プラグインのエコシステムのおかげで、シンプルに書ける面は多分にありますが、それほど本質的ではありません。

  • ファイルをvinylストリームで扱う
  • 非同期タスクの実行順序制御 (series, parallel)

この2点は、シェルスクリプトだけで実現するのは厄介なので、引き続きgulpを使う理由として残るように思います。特に前者について、複数ファイルの扱いが秀逸です。この点、シェルスクリプトではtarで固めるしかなく、キレイに書く方法があまりありません。

メモ: 後者については、npm-run-allを使う手もあります。

最近は、シェルスクリプト(sh/bash)を触らない人も多いので、JavaScriptのプロジェクトについてはタスクもJavaScriptで書くというのは自然な気もします。個人的な指針としては、npm scriptsに書ききれなくなった時はgulpの出番です。具体的には

  • 複数のファイルを扱う
  • 複数のツールを組み合わせる

といったシーンです。

WebPack, Parcelなどの包括的なツールの流行りで、元々のgulpの使い途だった、トランスパイル系の操作での需要は減っていますが、2018年も意外と(?)使いどころが残っているgulpでした。

168
134
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
168
134

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?