gulpfile.js をv4形式で書いてみる

Blog

うどんか蕎麦だったらギリ蕎麦派。どうもkikuchiです。

Gulpについて勉強している過程で「Gulp v4ではgulp.task()によるタスク定義は非推奨」という記事を見かけました。
参考記事:絶対つまずかないGulp 4入門(2019年版) インストールとSassを使うまでの手順

公式サイトにも記載されていますね、、

Reminder: This API isn’t the recommended pattern anymore – export your tasks.

引用元:https://gulpjs.com/docs/en/api/task/

これから新たにGulpを勉強するならGulp v4で推奨されている書き方を学ぼう!そうしよう!ということで、Gulpについて勉強したこと、gulpfile.jsの書き方についてまとめました。

Gulp(ガルプ)について

GulpはWebサイトを構築する上で必要なさまざまな処理※(タスク)を自動化するツールで、「タスクランナー」「ビルドシステムヘルパー」とも呼ばれています。
※さまざまな処理とは、Sassなどのコンパイル、JavaScriptを圧縮、構文チェック…等

Gulp公式サイト:https://gulpjs.com/


GulpはNode.jsのライブラリの一つで、Gulpを利用するにはまずNode.jsをインストールします。
ちなみに弊社ではNode.jsの管理をnodenvで、nodenvの管理をanyenvで行っています。
(2020年7月31日時点)


Node.jsとは、JavaScriptをブラウザ外で使用できるようにしたもの、サーバーサイドで動作する技術です。(JavaScriptはもともとブラウザ上で動く)

  • Node.jsでは「npm(Node Packaged Modules)」コマンドでパッケージのインストールを行う
    $ npm i パッケージ名(ローカルにインストール)
    $ npm i -g パッケージ名(グローバルにインストール)
    ※「i」=「install」の略
  • Node.jsの最新版(npm v5.2以上)だと「npx」コマンドが使用できる

Node.js公式サイト:https://nodejs.org/ja/
参考記事:JavaScriptをサーバサイドで動かせる!Node.jsの魅力とは?


続いてGulpのインストールについてです。(Node.jsがインストールされている前提で進めます)

作業環境

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.15
BuildVersion:   19A583

$ node -v
v12.18.2

$ npm -v
6.14.5
sample_project/(プロジェクトフォルダー)
 ∟ htdocs/
    ∟ css/
    ∟ js/
    ∟ index.html
 ∟ src/(開発環境)
    ∟ scss/
       ∟ style.scss
    ∟ js/
       ∟ script.js

gulpをインストール

インストールなどの操作はターミナルで行います。黒い画面、、!

(1)$ cd sample_project
gulpを動かしたいディレクトリ(プロジェクトフォルダー)に移動。

(2)$ npm init -y
package.json を生成。
※package.json とは npm でパッケージを管理するためのファイル

(3)$ npm i -D gulp
gulp本体をインストール。
これをインストールするとプロジェクトフォルダー直下に「node_modules」というフォルダー(npmコマンドで使えるパッケージが入っている)が生成されます。
※「-D」=「–save-dev」の略

(4)$ gulp -v
gulpのバージョンを確認。

$ gulp -v
CLI version: X.X.X
Local version: 4.X.X

(5)$ gulp
gulpコマンドを実行し正常に動作したらgulpのインストール完了。

もし「The `gulp’ command exists in these Node versions:」というようなエラーが出た場合は、そのプロジェクトで使用しているNode.jsのバージョンでgulpコマンドを使用出来るように $npm i -g gulp-cli を実行します。
※gulp-cliはあくまでターミナルでgulpコマンドを使用できるようにするだけのもの

gulpfile.js の中身

前提として、下記のタスクをgulpを通して自動化させるようにします。

  • SassをCSSにコンパイル
  • ベンダープレフィックス付与
  • CSSの中身を整理
  • ES6対応
  • JavaScript圧縮


ここでは、gulpfile.js の中身を大きく分けて下記の3つに分類して見ていきたいと思います。

  1. プラグイン読み込み
  2. タスクごとに関数を定義
  3. 関数を実行

1. プラグイン読み込み

現時点では、$ npm i -D gulp でGulp本体のパッケージをインストールして、その中に入ってるgulpプラグインだけがインストールされている、という状態です。
様々な処理を行うためには目的に合ったプラグインを使用する必要があるので、他のプラグインもインストールしていきます。

※下記のようにまとめてインストールすることも可能。
$ npm i -D gulp-sass gulp-sass-glob gulp-postcss autoprefixer

インストールしたプラグインはgulpfile.jsで下記のように記述して読み込みます。

【gulpfile.js】

const { src, dest, watch, parallel } = require('gulp');

//-- Sass
const sass = require('gulp-sass');                    // Sassをコンパイル
const sassGlob = require('gulp-sass-glob');   // パーシャルファイルを一括import
const postcss = require('gulp-postcss');       // PostCSSのプラグイン(autoprefixer/css-mqpacke 等)を通してCSSを自動整形

//-- JavaScript
const babel = require('gulp-babel');              // ES6記法を古いブラウザにも対応させる
const uglify = require('gulp-uglify');             // minify(圧縮)

コンパイルしたファイルの保存先を指定するため、あらかじめディレクトリを変数化しておきます。

const filepath = { src: 'src/', dist: 'htdocs/' };
const filesrc = {
  css: `${filepath.src}scss/**/*.scss`,
  js: `${filepath.src}js/*.js`,
};

2. タスクごとに関数を定義

Sassに関するタスク

const css = () => {
  return src(filesrc.css)
    .pipe(sassGlob())
    .pipe(
      sass({
        outputStyle:'expanded'
      }).on('error', sass.logError)
    )
    .pipe(
      postcss([
        require('autoprefixer')({
          grid: 'autoplace',
          cascade: false
        }),
        require('css-mqpacker')
      ])
    )
    .pipe(dest(`${filepath.dist}css/`));
};

上から順に解説すると、

  • 以下の{}内の内容の関数を作って、新規作成した変数「css」に入れろ
  • src/scss/ 内のファイルの中身を全て見ろ
  • sassGlob:パーシャルファイルを一括importせよ
  • sass:Sassのコンパイル実行、オプションでコンパイル後のスタイル(expanded)指定、errorが起きた時にSassのコンパイルエラーを表示せよ(これがないと後述するwatchが自動的に止まってしまう)
  • postcss:ベンダープレフィックス付与するプラグイン(autoprefixer)と、メディアクエリーをまとめるプラグイン(css-mqpacker)読み込め
  • 最後に htdocs/css/ フォルダに書き出せ

JavaScriptに関するタスク

const js = () => {
  return src(filesrc.js)
    .pipe(
      babel({
        presets: ['@babel/preset-env']
      })
    )
    .pipe(uglify())
    .pipe(dest(`${filepath.dist}js/`));
};
  • 以下の{}内の内容の関数を作って、新規作成した変数「js」に入れろ
  • src/js/ 内のファイルの中身を全て見ろ
  • babel:ES6記法を古いブラウザにも対応させろ
  • uglify:JavaScriptファイルを圧縮せよ
  • 最後に htdocs/js/ フォルダに書き出せ

3. 関数を実行

最後に先ほど定義した関数を実行させる処理を書きます。

//-- `$ gulp` で全てのタスクを実行
exports.default = parallel(css, js);

//-- `$ gulp css` `$ gulp js` で個別にタスクを実行
exports.css = css;
exports.js = js;

//-- `$ gulp w` でファイルの変更を監視してタスクを自動で実行
exports.w = function () {
  watch(filesrc.css, css);
  watch(filesrc.js, js);
};

ターミナルで $ gulp w と打つと、ファイルを常に監視し、ファイル内で何か変更が起きた場合これまで定義したタスクを自動で実行するようになります!ブラボー!


途中で出てきたよく分からない単語 parallel
調べてみると、Gulp v4から parallel ともう一つ series という機能が追加されたようです。
はて、これらは一体何が出来るのでしょうか、、?

series とは

直列に処理を実行します。
書き方例:gulp.series(タスク1, タスク2);

例えば、タスク1(babelで変換)を処理した後にタスク2(JavaScriptファイルを圧縮)を処理する、など順番を指定しなければならない時にseriesを使用します。
※今回の記事内ではタスクの関数を定義した段階で関数内で上から順に処理をしていくように書いており、seriesを指定するほど複雑な処理をしていないので未使用です。

parallel とは

並列に処理を実行します。
書き方例:gulp.parallel(タスク1, タスク2);

例えば、タスク1(CSSに関するタスク)とタスク2(JavaScriptに関するタスク)は処理内容が異なり同時に処理をしても問題ないためparallelで処理します。


参考記事:gulp 4.0から新しく加わったseriesとparallelについての備忘録

まとめ

と言うことで、gulpfile.js の全貌はこのようになります。

//---------------------------------------------------
// Plugin
//---------------------------------------------------

const { src, dest, watch, parallel } = require('gulp');

//-- Sass
const sass = require('gulp-sass');
const sassGlob = require('gulp-sass-glob');
const postcss = require('gulp-postcss');

//-- JavaScript
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');



//---------------------------------------------------
// Directory
//---------------------------------------------------

const filepath = { src: 'src/', dist: 'htdocs/' };
const filesrc = {
  css: `${filepath.src}scss/**/*.scss`,
  js: `${filepath.src}js/*.js`,
};



//---------------------------------------------------
// task
//---------------------------------------------------

//-- Sassに関するタスク
const css = () => {
  return src(filesrc.css)
    .pipe(sassGlob())
    .pipe(
      sass({
        outputStyle:'expanded'
      }).on('error', sass.logError)
    )
    .pipe(
      postcss([
        require('autoprefixer')({
          grid: 'autoplace',
          cascade: false
        }),
        require('css-mqpacker')
      ])
    )
    .pipe(dest(`${filepath.dist}css/`));
};

//-- JavaScriptに関するタスク
const js = () => {
  return src(filesrc.js)
    .pipe(
      babel({
        presets: ['@babel/preset-env']
      })
    )
    .pipe(uglify())
    .pipe(dest(`${filepath.dist}js/`));
};



//---------------------------------------------------
// 実行
//---------------------------------------------------

//-- `$ gulp` で全てのタスクを実行
exports.default = parallel(css, js);

//-- `$ gulp css` `$ gulp js` 個別にタスクを実行
exports.css = css;
exports.js = js;

//-- `$ gulp w` でファイルの変更を監視してタスクを自動で実行
exports.w = function () {
  watch(filesrc.css, css);
  watch(filesrc.js, js);
};

シンプル イズ ザ ベスト!
あとはお好みでプラグインを追加したり煮るなり焼くなりしてみてください。


ちなみに、gulpfile.jsを書き終えていざgulpを動かすぞ!とコマンドを打った後に下記のようなエラーが出る方もいらっしゃると思います。。

Error in plugin "gulp-babel"
Message:
    Cannot find module '@babel/preset-env' from '/~/sample_project'

これは必要なプラグインがインストール出来ていない、この場合「sample_project(プロジェクトフォルダー)」内に「@babel/preset-env」というプラグインがありませんよ〜!ということなので、このようなエラーが出た時はプラグインをインストールしましょう。

$ npm i -D @babel/preset-env


一通り勉強したつもりではいますが、Gulpについて完全に理解した!とまではまだ言えません(涙)
package.jsonの中身とかちんぷんかんぷんです…。勉強します…!
それでも開発環境に対する理解が少しでも進むとエンジニアレベルが若干上がった気がします。ポケモンで言うとフシギダネからフシギソウになった感じですかね。はい。