gulpについて理解を深めたい

# はじめに
はじめまして。
9月の中旬にエンジニアとして株式会社アンティー・ファクトリーに入社しました。
今回はタイトルにもある通り、gulpについて理解を深めたいと思います。

まず、弊社では開発する際に使用するテンプレートがあり、gulpなどの便利なツールが内蔵されています。
先輩から教わったとおりにスクリプトを打ち込み、gulpを動かして制作するのですが、度々
「何がどう動いてどうなっているのか分からない」「変なとこいじっちゃってやばいことになったらやばい」
と不安になることがあるので、この記事ではgulpについての理解を深めていきたいです。

# やること
まず今回やることはこれです。
- Sass、ejsのコンパイルの自動化
- ローカルサーバーの立ち上げ
- タスクの同時実行

の3点です。
# バージョン
node.js 16.17.0
npm 8.15.0

# フォルダ構成
![スクリーンショット 2022-11-28 14.13.58.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854155/b4ba403d-9013-a52c-1507-4ac03dbacae3.png)
今回はgulpをタスクごとにファイル分けするため、gulpfile.jsというフォルダーを作成し、その中にファイルをどんどん入れていこうと思います。

# 下準備
今回使用するディレクトリに移動します。
```
$ cd file
```
### package.jsonの作成
下記のコマンドを入力すると質問攻めに遭います。質問に答えると、package.jsonが作成されます。
質問攻めを回避したい場合は`npm init -y`と入力。
```
$ npm init 
```
```package.json
{
  "name": "file",
  "version": "1.0.0",
  "description": "gulpの練習",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}
```
### gulpのインストール
続いてgulpをインストールします。
`--save-dev`をつけるとpackage.jsonの`devDependencies`の部分にインストールされたモジュールが記述されます。
```
$ npm install gulp --save-dev
```
このようになっていたらOK。
```package.json
{
  "name": "file",
  "version": "1.0.0",
  "description": "gulpの練習",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "gulp": "^4.0.2"
  }
}
```
# Sass、ejsのコンパイル自動化
#### gulpの設定
本来はgulpfile.jsというファイルの中にタスクを記述するのが一般的かと思いますが、タスクごとにファイル分けすることで、コードの可読性やファイル構造の理解しやすさが上がるのではないかと思ったのでそのように進めていきます。

では、gulpfile.jsの中に移動し、index.jsを作成します。
```
$ cd gulpfile.js
$ touch index.js
```
続いてindex.jsに
```index.js
const gulp = require('gulp');
```
と記述します。これでgulpを使えるようになりました。
#### Sassのコンパイル
次に、Sassをコンパイルするタスクを記述するファイルを作成します。ファイル名はsass.jsとします。
```
$ touch sass.js
```
さらに、Sassをコンパイルするためのモジュールをインストールします。
```
$ npm install gulp-sass --save-dev
$ npm install sass --save-dev
$ npm install gulp-source-maps --save-dev
```
`gulp-sass`、`sass`はSassをコンパイルするためのモジュールで`gulp-sourcemaps`はソースマップを作成するためのモジュールです。

インストールが完了したら、作成したsass.jsに下記のように記述していきます。
```sass.js
const gulp = require('gulp');
const sass = require('gulp-sass')(require('sass'));
const sourcemaps = require('gulp-sourcemaps');

const style = (done) => {
    gulp.src("src/scss/**/*.scss")
        .pipe(sass({outputStyle: 'expanded'}))
        .pipe(sourcemaps.init())
        .pipe(sourcemaps.write('./'))
        .pipe(gulp.dest("dest/css/"));
    done();
};

exports.style = style;
```
`style`という関数では
- `gulp.src()`というメソッドでコンパイルしたいファイルの読み込み
- `.pipe(sass({outputStyle: 'expanded'}))`で、コンパイルされたファイルの記法を指定
- `.pipe(sourcemaps.init())`でソースマップの作成
- `.pipe(sourcemaps.write('./'))`でソースマップを作成するパスの指定
- `.pipe(gulp.dest("dest/css/"))`でコンパイルされたファイルを設置するパスの指定

をしています。

今回は`dest`というフォルダの中に`css`というフォルダを作成し、その中にコンパイルされたファイルを置くように指定しています。
続いて、index.jsに
```index.js
const gulp = require("gulp");
const { style } = require('./sass'); //追加

exports.style = style; //追加

exports.default = gulp.series( 
 style
); //追加
```
コメントアウトされている部分を追加します。

記述できたら試運転です。
ターミナルやコマンドプロンプトに
```
$ gulp style
```
と入力します。
![スクリーンショット 2022-11-28 11.57.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854155/1b2b5b24-4c86-6f2c-8cc4-fcf369299f71.png)
上記の画像のようになり、`dest`フォルダ内に`css`フォルダが設置され、コンパイルされたcssとcssのソースマップが作成されていれば成功です。
#### ejsのコンパイル
次に、ejsのコンパイルをしていきます。
手順としては、先ほどのSassと大体同じです。
```
$ touch ejs.js
```
ejsをコンパイルするタスクを記述するファイルを作成。
```
$ npm install gulp-ejs --save-dev
$ npm install gulp-rename --save-dev
```
使用するモジュールをインストールします。
インストールできたら、作成したejs.jsに
```ejs.js
const gulp = require('gulp');
const ejs = require('gulp-ejs');
const rename = require('gulp-rename');

const markup = (done) => {
    gulp.src("src/ejs/**/*.ejs","!src/ejs/**/_*.ejs")
        .pipe(ejs())
        .pipe(rename( { extname: ".html"} ))
        .pipe(gulp.dest('dest/html/'));
    done();
};

exports.markup = markup;
```
と記述します。
`markup`という関数では、
 - `gulp.src("src/ejs/**/*.ejs","!src/ejs/**/_*.ejs")`でコンパイルするフォルダの読み込み
    （第二引数では、`_.ejs`とあるように`_`がついているファイルをコンパイルしないように指定)
 - `.pipe(ejs())`でejsのコンパイル実行
 - `.pipe(rename( { extname: ".html"} ))`で拡張子を`.ejs`から`.html`に書き換え
 - `.pipe(gulp.dest('dest/html/'));`でコンパイルされたファイルを設置するパスの指定

をしています。
そして、index.jsに
```index.js
const gulp = require("gulp");
const { style } = require('./sass');
const { markup } = require('./ejs'); //追加

exports.style = style;
exports.markup = markup; //追加

exports.default = gulp.series(
 style,markup //追加
);
```
コメントアウトされている部分を追加します。
記述できたら、試運転です。
ターミナルやコマンドプロンプトに
```
$ gulp markup
```
と入力します。
![スクリーンショット 2022-11-28 12.46.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854155/64234d22-b203-68ef-d196-03ed149b5edd.png)
上記の画像のようになり、`dest`フォルダ内に`html`フォルダが設置され、コンパイルされたhtmlファイルが作成されていれば成功です。

# ローカルサーバーの立ち上げ
次にローカルサーバーを立ち上げるタスクを記述していきます。
```
$ touch server.js
```
ファイルを作成します。
```
$ npm install browser-sync --save-dev
```
使用するモジュールをインストールします。
server.js内に下記のように記述します。
```server.js
const { series,watch } = require('gulp');
const browserSync = require('browser-sync').create();
const { markup } = require('./ejs');
const { style } = require('./scss');

const browserReload = callback => {
    browserSync.reload();
    callback();
  };

const serve = () => {
    browserSync.init({
        open:false,
        startPath:'',
        reloadDelay:1000,
        once:true,
        notify:true,
        ghostMode:false,
        server: {
            baseDir:"dest/",
        },
    });

    watch('src/ejs/**/*.ejs', { usePolling: true }).on('change', series(markup, browserReload));
    watch('src/scss/**/*.scss', { usePolling: true }).on('change', series(style, browserReload));
};
exports.serve = serve;
```
ターミナルに下記のように入力します。
```
$ gulp serve
```
![スクリーンショット 2022-11-28 14.41.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854155/4c6a2c9c-d516-5535-e1a6-8f9604ef402a.png)
上記の画像のように表示されていれば成功です。

# 同時実行
ここまでさまざまなタスクを作成してきましたが、最後に今までの処理を同時に実行したいと思います。
理想としては、
- 一旦`dest`フォルダの`html`フォルダ、`css`フォルダを削除
- `src`フォルダの`ejs`フォルダ、`scss`フォルダ内のファイルをコンパイル
- ローカルサーバーの立ち上げ
- 監視状態に移行

という処理を一度に実行できるようにしたいです。
### 手順
まずは必要なモジュールをインストールします。
```
$ npm install rimraf --save-dev
```
インストールできたら、`package.json`の`"scripts"`の部分に記述していきます。
```package.json
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "clean": "rimraf dest/html/ & rimraf dest/css/",
    "compile": "gulp markup && gulp style", 
    "dev" : "npm run clean && npm run compile && gulp serve" 
  }
```
`clean`というコマンドで`dest`フォルダ内の`html`フォルダ、`css`フォルダを削除し、
`compile`というコマンドでejsとSassのコンパイルを行なっています。
`dev`というコマンドでは先ほどの`clean`と`compile`を順に行い、最後にローカルサーバーを立ち上げています。

記述できたらコマンドプロンプトやターミナルに下記のコマンドを入力します。
```
$ npm run dev
```
![スクリーンショット 2022-11-28 15.18.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2854155/c0b2a4e5-5763-ece1-8fe2-5e3871c35e80.png)
上記の画像のように`markup`タスク、`style`タスク、`serve`タスクが順に実行され、ローカルサーバーが立ち上がり、監視状態に移行していれば成功です。
# 感想
実際に自分で環境を構築してみて、gulpについて未だ分からない部分はありますが、理解度は上がったのかなと思います。本当は、ファイル名が変更されたら出力先のファイル名も変更されるタスクも作成したかったのですが、自分の実力不足で完成には至りませんでした。他にも、足りない部分や実装すべきタスクや機能はまだまだあると思いますので、もっと知識を吸収してどんどん機能を足していけたらいいなと思いました。予想以上に長くなりましたが、ここまで読んでいただきありがとうございます。