Gulpはタスクランナーである。JSに軸足を置くバンドラー(Webpackなど)やビルドツール(Viteなど)とは異なり、Web制作のさまざまなタスクを並列的に処理できる。
バンドラー(Webpackなど)との違い
バンドラーは、文字通りバンドルをするためのツールであり、タスクランナーはタスクを走らせるためのツールである。
バンドルはタスクの一種だ。タスクランナーからバンドラーを使うことはできるが、その逆はできない(できるかもしれないが、普通はやらない)。
各種トランスパイルに対応したり、テストサーバーを起動したり、タスクランナーと重なる機能をバンドラーも持っている。ただ、その主眼はJavaScriptを使ったアプリ開発にある。
HTML/CSSでゴリゴリWebページを作りたい場合には、タスクランナーの方が適している。
と私は思う。
Gulpは古いのか?
古い。Webpackも古い。CSSも古いし、HTMLはもっと古い。時間が経てばなんだって古くなる。
ゲシュタルト崩壊した。改めて見ると古いって怖い形の漢字だ。呪いに使われそうである。
Gulpは確かに古く、プラグインの中にも、メンテナンスされているのかいないのかわからないものが散見される。時代遅れとまでは言えないが、ピークは去った。
ただ、Gulpの最新バージョンは2024年3月29日にリリースされたばかりである。更新されないプラグインも、現実から目を背ければ機能が成熟したのだと解釈できる(白目)。ともかく、まだまだ使えるツールであることは間違いない。
インストール方法
Gulpを動かすには、コマンドラインツールであるgulp-cli
と、本体のgulp
というNPMモジュールが必要だ。
まずgulp-cli
をグローバルインストールする(気持ちが悪ければ、ローカルでも良い)。
次にgulp
を入れる。
準備おしまい。
使い方
Gulpでは、プロジェクトのルートディレクトリにgulpfile.js
(あるいはGulpfile.js
)というファイルを置き、その中に実行したいタスクを関数として定義する。
JavaScriptには、ファイルをインポートしたりエクスポートしたりする仕組みが大きく2つある。require()
関数とexports
オブジェクトを使うCommonJSと、import/export
キーワードを使うES Modulesである。
GulpはJavaScriptで書かれているため、どちらも使える。ただ、GulpのドキュメントはCommonJSで統一されているようなので、本記事でもそれに倣う。
上記のコードは、コマンドライン上のgulp
コマンドで実行できる。gulp-cli
をローカルに入れた場合はnpx gulp
とする。
実行すると、以下のように処理内容が出力されるはずだ。
タスクについて
Gulpのタスクは、JavaScript関数として定義する。この関数は、非同期処理を含んでいなくても、非同期的に処理される(昔は同期関数は同期関数として実行できたが、現在ではすべてのタスクが非同期的に管理される)。
そのため、必要に応じてタスクの完了をGulpに通知せねばらならない。引数に完了通知用のコールバック関数を受け取って実行するか、Promise
やストリーム(やイベントエミッターや子プロセスやObservable)を返すか、そもそもasync
をつけて関数を定義してやる必要がある。
関数をGulpのタスクとして実行できるようにするには、以下のようにexports
オブジェクトのプロパティとして代入する。
default
に代入したものはgulp
コマンドで、それ以外の任意のプロパティに代入したタスクはgulp プロパティ名
コマンドで実行できる。
series()とparalell()
複数のタスクをまとめて実行したい時には、series()
関数やparalell()
関数を使う。
タスクの合成に使う関数 | 概要 |
---|---|
series(task1,task2,...) |
引数に渡されたタスク(関数)を連続して実行する。前の関数の処理が終わらないと、次の関数は実行されない。 |
paralell(task1,task2,...) |
引数に渡されたタスク(関数)を並列的に実行する。 |
両者は組み合わせて使うこともできる。
これを実行すると、以下のような結果が出力されるはずである。
並列処理と逐次処理が適切に実行されていることがわかる。
src()とdest()とpipe()
Gulpでは、Vinylという仮想的なファイルフォーマットを使ってファイルを操作する。
操作の軸となるのは、Gulpのsrc()
とdest()
、それからNode.jsのpipe()
という3つの関数である。
ファイル操作に使う関数 | 概要 |
---|---|
src(globs[, options]) | 第一引数に渡されたパスにマッチするファイルをVinylオブジェクトとして読み込み、そのオブジェクトを保持する読み取り可能なストリームオブジェクトを返す。 |
dest(folder[, options]) | 第一引数に渡されたディレクトリにVinylオブジェクトを出力する書き込み可能なストリームオブジェクトを返す。 |
readable.pipe(destination[, options]) | 書き込み可能な(あるいは読み書き可能な)ストリームを受け取り、読み取り可能な(あるいは読み書き可能な)ストリームに転送する。 |
"glob"(グロブ)は、文字列特定の記号を用いて文字列のパターンを表現する方法である。大元であるUnixの記法が踏襲されるものの、細部はglobを採用するツールによって異なる。ちなみにglobはglobalの略語だそうである。
Gulpの場合、以下のような記号を使う。
記号の種類 | 意味 |
---|---|
/ |
セグメントの区切り文字。 |
* |
1つのセグメントに含まれる0文字以上の文字列。 |
** |
複数のセグメントに跨る0文字以上の文字列。 |
! |
そのglobの否定(マッチしないものにマッチ)。 |
例えば、静的ファイルをソースディレクトリからpublicディレクトリにコピーしたい時は、以下のように書く。
実際には、src()とpipe(dest(‘xxx’))の間にプラグインの処理を挟んで、望む処理を形にしていく。
watch()
ディレクトリやファイルを監視して、任意のタスクを実行したい時には、watch()
関数を使う。
監視に使う関数 | 概要 |
---|---|
watch(globs[, options, task]) | 指定されたglobにマッチするファイル、あるいはディレクトリを監視し、対応するタスクを実行するよう設定する。その上で、設定を細かく制御するためのchokidarオブジェクトを返す。 |
第2引数のoptions
には、以下のような属性値を指定できる(値はデフォルト値)。
第3引数のtask
には、任意のタスク関数か、series()
あるいはparallel()
で作成した複合タスクを指定する。
なお、watch()
関数が返すchokidar
インスタンスは、Gulpが内部で使っているファイル監視用ライブラリのオブジェクトである。chokidar
という名称は、ヒンディー語で門番とか番人とかいう意味を持つ単語らしい。グーチョキパーのチョキは関係ない。
先のoptions
は、厳密にはwacth()
関数ではなくchokidar
インスタンスためのオプションだったりする。
chokidar
watch()
関数を使うと、ファイルやディレクトリの変化に応じて任意のタスクを実行できる。ただ、変化したファイルやディレクトリに絞って任意のタスクを実行するには、それらのパスを取得し、別途src()
で読み込んでやる必要がある。
パスは、chokidar
インスタンスのon()
メソッドで監視用のイベントリスナを登録し、その引数として受け取ることができる。
on
メソッドでは、以下のようなイベントをリッスンできる。
イベント名 | 概要 |
---|---|
add |
ファイルの追加。 |
addDir |
ディレクトリの追加。 |
change |
ファイルの変更。 |
unlink |
ファイルの削除。 |
unlinkDir |
ディレクトリの削除。 |
ready |
初期スキャン完了。 |
error |
エラー。 |
all |
ぜんぶ。 |
また、イベントリスナは以下の2つの引数を受け取る。
引数 | 概要 |
---|---|
path |
変更されたファイルのパス。 |
stats |
読み込んだファイルのfs.Statオブジェクト。 |
また、唐突に出てきたts = require("gulp-typescript");
はGulpのプラグインである。ここでのプラグインは、有志によって作られた、使用頻度の高い普遍的なタスクを指す。
プラグイン
Gulpのプラグインは、Gulpとは独立したNode.jsパッケージである。多くはgulp-
という接頭辞がついている。
必要に応じてパッケージをインストールし、gulpfile.js
にインポートして使う。代表的なプラグインをいくつかピックアップしてみる。
gulp-pug | PugをHTMLにトランスパイルするプラグイン。 |
gulp-sass | SASSをCSSにトランスパイルするプラグイン。 |
gulp-typescript | TypeScriptをJavaScriptにトランスパイルするプラグイン。 |
browser-sync | Gulpプラグインではないが、開発サーバとしてGulpと組み合わせてよく使われる。 |
gulp-pugの使い方
まず必要なパッケージをインストールする。
必要な関数をインポートして使う。
どのプラグインも、この流れはおおよそ共通している。オプションはがんばってドキュメントを読み解いて使う。
gulp-sassの使い方
以下同文。と思ったけど単純に関数をインポートしただけでは使えないものもある。やっぱり、個々にドキュメントを読んでがんばるしかない。
gulp-typescirptの使い方
以下同文。
browser-syncの使い方(ブラウザの自動リロード)
GulpのタスクはただのJavaScript関数であるので、Gulpプラグインとして作られていないものであってもタスクとして指定できる。
このケースではストリームを返さないので、コールバックを実行してタスクの完了を通知する必要がある。
また、このケースに限らないが、ファイルやディレクトリを指定するのに、globを使うものと普通の相対パスを使うものとで混乱しやすい点にも注意が必要である。