見出し画像

gulp.jsの環境構築したので初心者向けにまとめてみる

私も初心者だった頃に挫折を味わったgulp.jsの環境構築に、歴8年目にして再チャレンジしたので、解説を交えて方法をまとめていきます。

※(2023.05.26)ファイル削除をdelではなくfsに変更しました。

やりたいこと

  • Sassのコンパイルと圧縮(とソースマップの生成)

  • JSの圧縮(とソースマップの生成)

  • HTMLの複製

  • Browsersyncの利用

  • (おまけ)EJSのコンパイル

とりあえずgulp入門としてコーディング初心者が使うために最低限必要そうなことだけ盛り込んでます。
順を追ってやっていけば誰でも環境構築ができちゃう&コードの意味もちょっと理解できちゃうように書いてみようと思います。


作業環境

Windows10のコマンドプロンプトを使用します。
Macのターミナルとは少しコマンドが違う部分もあるかもしれません。

WindowsとMacの違いやnode.jsのインストール方法などは割愛します。あしからず。

ちなみにnode.jsとnpmのバージョンは下記の通りです。


node v18.16.0
npm 9.5.1


最初に作業用のフォルダに移動し、下記のコマンドを実行してpackage.jsonを作成してください。

npm init -y


gulpのインストール

npm i -D gulp

インストールしたバージョンは下記の通り


CLI version: 2.3.0
Local version: 4.0.2



設定ファイルを作る

インストールが終わったらpackage.jsonと同じ場所にgulpfile.jsを作成して下記を記述します。

const { src, dest, watch, parallel, series } = require("gulp")


フォルダ構成

下記のような構成で進めていきます。


folder
├ dest
│ ├ css
│ └ js
├ node_modules
├ src
│ ├ html
│ │ ├ about
│ │ │ └ index.html
│ │ └ index.html
│ ├ js
│ │ └ script.js
│ └ sass
│   ├ components
│   │ └ _card.scss
│   ├ layout
│   │ └ _body.scss
│   └ style.scss
├ gulpfile.js
├ package-lock.json
└ package.json


では始めます。

Sassのコンパイル

インストール

sassとgulp-sassをインストールします。

npm i -D sass gulp-sass

インストールが終わったらgulpfile.jsに下記を追記します。

const sass = require('gulp-sass')(require('sass'));

const compileSass = () => {
  return src("./src/sass/**/*.scss", { sourcemaps: true })
    .pipe(sass({ outputStyle: "compressed" }).on("error", sass.logError))
    .pipe(dest("./dest/css", { sourcemaps: "." }))
}

exports.default = compileSass

※scssではなくsassを使用される方は拡張子に注意してください。

そして下記を実行するとdestフォルダにcssフォルダが作成されcssファイルがコンパイルされます。

npx gulp


ざっくり解説①

returnで作成したストリームを返します。(returnしないと「タスクが終わったのかわからないよ!」と言われてエラーになります)

src()は引数に指定したファイルを探して集めます。
今回は第二引数にソースマップを作成するようにオプションを指定しています。

「*」(single-star)は任意の文字数にマッチしますが、一つのセグメント(フォルダ内)に限定されます。

「**」(double-star)
をつけることで、src/sass直下の.scssファイルも、src/sass配下(階層はどこまでも)のフォルダの中にある.scssファイルにもマッチするようになります。

次に.pipe()の中に実行したいタスクを記述して繋げていきます。
(改行していますがコードはひと続きになっています)

sass()にはオプションの{ outputStyle: "compressed" }で圧縮するように設定して、.on("error", sass.logError)でエラーが起きた時はそのエラーログを提示してもらうようにしています

そしてdest()でコンパイルしたファイルとソースマップをdest/cssに入れます。

最後に、exports.defaultに代入します。


記述を変更したら自動でコンパイル

gulpfile.jsに下記を追記します。
(修正部分は - の行を削除して + の行を追加してください)

//追加
const watchFiles = () => {
  watch("./src/sass/**/*.scss", { ignoreInitial: false }, compileSass)
}

//修正
- exports.default = compileSass
+ exports.default = watchFiles

再度gulpを実行してscssファイル内の記述を変更して保存してください。
cssの記述も変わっていたら成功です。


ざっくり解説②

watch()は第一引数に指定したファイルを監視して、変更があれば第三引数に指定したタスクを実行してくれます。(オプションが無い時は第二引数にタスクを指定します)
そのままだと最初にwatchを実行した時にはタスクが実行されないので第二引数にオプションでignoreInitial: falseを指定して最初にタスクが実行されるようにしています。


エラーが出ても中断させない

現状のままだとせっかくwatchしてもエラーが出ると中断してしまって、修正して再度watchを実行しないといけません。
そこでエラーが出ても中断しないように改良します。

まず下記をインストールします。

npm i -D gulp-plumber gulp-notify

そしてgulpfile.jsに.タスクを追加します。

//追記
const plumber = require("gulp-plumber")
const notify = require("gulp-notify")

//修正
const compileSass = () => {
  return src("./src/sass/**/*.scss", { sourcemaps: true })
-   .pipe(sass({ outputStyle: "compressed" }).on("error", sass.logError))
+   .pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
+   .pipe(sass({ outputStyle: "compressed" }))
    .pipe(dest("./dest/css", { sourcemaps: "." }))
}

もう一度watchを実行してください。
エラーが出ても中断せず、修正すれば自動でコンパイルされて作業を続けられれば成功です。


ざっくり解説③

sass()の後ろにあったエラーログに関する記述.on("error", sass.logError)を削除し、plumber()errorHandlerオプションにnotify.onError("Error: <%= error.message %>")を指定してエラーを表示させています。


JSの圧縮

次はJSを圧縮させます。

インストール

下記をインストールしてください。

npm i -D gulp-uglify

そしてgulpfile.jsに追記します。

const uglify = require("gulp-uglify")

const minifyJs = () => {
  return src("./src/js/*.js", { sourcemaps: true })
    .pipe(uglify())
    .pipe(dest("./dest/js", { sourcemaps: "." }))
}

JSもSassと同じくソースマップを生成し、pipe()でugifyを繋いで圧縮したものをdest/jsに入れています。

watchFilesにJSのwatchを追加します。(Sassの部分は削除しません)

//修正
const watchFiles = () => {
  watch("./src/sass/**/*.scss", { ignoreInitial: false }, compileSass)
+ watch("./src/js/*.js", { ignoreInitial: false }, minifyJs)
}

追加できたらgulpを実行してちゃんと動くか確認してください。


HTMLを複製

さあどんどん行きましょう。

今度はsrc/htmlに作成したhtmlファイルをdest/に出力します。
圧縮してもいいですが、今回はそのまま複製するだけにします。

gulpfile.jsを変更します。

//追加
const copyHtml = () => {
  return src("./src/html/**/*.html")
    .pipe(dest("./dest"))
}

//修正
const watchFiles = () => {
  watch("./src/sass/**/*.scss", { ignoreInitial: false }, compileSass)
  watch("./src/js/*.js", { ignoreInitial: false }, minifyJs)
+ watch("./src/html/**/*.html", { ignoreInitial: false }, copyHtml)
}

HTMLはそのまま複製するだけなので特に難しいことはないですね。


Browsersyncの設定

今のままだとブラウザをリロードしないと変更が反映されないので、オートリロード機能を追加したいです。
さらに、別の端末でも表示や動作が確認できるようになってくれると嬉しいですよね。

そんな時に便利なのがBrowsersyncです。


インストール

では早速インストールします。

npm i -D browser-sync

gulpfile.jsに追記していきます。

//追加
const browserSync = require("browser-sync")
const reload = browserSync.reload

//修正
const watchFiles = () => {
- watch("./src/sass/**/*.scss", { ignoreInitial: false }, compileSass)
- watch("./src/js/*.js", { ignoreInitial: false }, minifyJs)
- watch("./src/html/**/*.html", { ignoreInitial: false }, copyHtml)
+ watch("./src/sass/**/*.scss", { ignoreInitial: false }, compileSass).on("change", reload)
+ watch("./src/js/*.js", { ignoreInitial: false }, minifyJs).on("change", reload)
+ watch("./src/html/**/*.html", { ignoreInitial: false }, copyHtml).on("change", reload)

+ browserSync.init({
+   server: {
+     baseDir: "./dest",
+   },
+ })
}

gulpを実行してブラウザが立ち上がれば成功です!

ちなみに別端末で表示させたい場合は、Browsersyncが起動した時に表示されたExternal:のURLを、いま使用しているPCと同じWi-Fiに接続した端末のブラウザのアドレスバーに入力してアクセスします。
(下記と同じものがコマンドプロンプトに表示されているはず)


[Browsersync] Access URLs:
-------------------------------------
    Local: http://localhost:3000
External: http://192.168.0.15:3000
-------------------------------------
              UI: http://localhost:3001
UI External: http://localhost:3001
-------------------------------------
[Browsersync] Serving files from: ./dest



ざっくり解説④

watchFilesの各watchにイベントを設定します。
今回は監視しているファイルに変更があったらBrowsersyncのreload(const reload = browserSync.reload)を実行させたいので.on("change", reload)を追加しています。

また、Browsersyncを起動させるためにbrowserSync.init()を実行し、表示させたいルートディレクトリをserverbaseDirプロパティの値に設定します。


buildコマンドの作成

さて、最後に公開用にソースマップなしのデータを作成します。

これまで作成したgulpfile.jsのSassとJSのコードを複製して、ソースマップを生成しないものに変更します。

//Sassのコンパイル
const buildSass = () => {
  return src("./src/sass/**/*.scss")
    .pipe(sass({ outputStyle: "compressed" }))
    .pipe(dest("./dest/css"))
}

//JSの圧縮
const buildJs = () => {
  return src("./src/js/*.js")
    .pipe(uglify())
    .pipe(dest("./dest/js"))
}

次にすでに生成されているソースマップファイルを削除したいので、delというパッケージを使用したかったのですが、どうやらバージョンアップしてES Modulesの仕様に変更されたようで、require()するとエラーが出てしまいます。(ちなみにrequire()はCommonJSの仕様です)

ということでNode.jsが提供しているfsモジュールを使います。

gulpfile.jsに追記します。

const fs = require("fs")

const deletFiles = async (cb) => {
  const filesToDelete = ["./dest/css/style.css.map", "./dest/js/script.js.map"]

  let deletedCount = 0

  filesToDelete.forEach((filePath) => {
    fs.unlink(filePath, (err) => {
      if (err) {
        console.error(err)
      } else {
        console.log(`Deleted file: ${filePath}`)
        deletedCount++
        if (deletedCount === filesToDelete.length) {
          console.log("All files deleted successfully")
          cb()
        }
      }
    })
  })
}

そしたら次はgulpにbuildコマンドに設定します。

exports.build = parallel(buildSass, buildJs, deletFiles)

buildは下記のコマンドで実行できます。

npx gulp build


ざっくり解説⑤

filesToDeleteに削除したいファイルを配列の形式で記述します。

forEach()メソッドでfilesToDeleteに入れたファイルに対してfs.unlink()を実行します。

完了したことがわかるようにdeletedCountにカウンターを設定しています。
deletedCountがfilesToDeleteの要素の数と同じになったら完了を知らせるcb()を実行します。

今回はexports.buildにして、npx gulp buildで実行します。


extra1:EJSのコンパイル

せっかくgulpを使うんだからテンプレートエンジンを使いたい方向けにEJSをコンパイルするコードも作ってみました。

テンプレートエンジンを使うくらいのレベルになればこれくらいすぐに書けると思いますけど笑


インストール

ではまずはインストール。

npm i -D gulp-ejs gulp-rename

そしてgulpfile.jsに追記。

const ejs = require("gulp-ejs")
const rename = require("gulp-rename")

const compileEjs = () => {
  return src("./src/ejs/**/*.ejs")
    .pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
    .pipe(ejs())
    .pipe(rename({ extname: ".html" }))
    .pipe(dest("./dest"))
}


ざっくり解説⑥

EJSをコンパイルしたあとに拡張子を.htmlに変更する必要があるのでpipe()でrename()を繋いでオプションにextname: ".html"を指定します。

あとはcompileEjsをwatchやbuildに追加すればOKです。


extra2:npm-scriptsで実行

package.jsonのscriptsにエイリアスを記述して、npm startnpm run buildなどのお馴染み(?)のコマンドでgulpを実行できるようになります。

"scripts": {
    "build": "npx gulp build",
    "start": "npx gulp"
  },

ちなみに今回使用したパッケージのバージョンは下記の通りです。

"devDependencies": {
    "browser-sync": "^2.29.3",
    "gulp": "^4.0.2",
    "gulp-ejs": "^5.1.0",
    "gulp-notify": "^4.0.0",
    "gulp-plumber": "^1.2.1",
    "gulp-rename": "^2.0.0",
    "gulp-sass": "^5.1.0",
    "gulp-uglify": "^3.0.2",
    "sass": "^1.62.1"
  }


あとがき

今回はとてもシンプルな構成なのでスムーズに環境構築できました(個人の感想です)

ちなみにコードはほとんど公式ドキュメントに書いてあるものを持ってきているので、よくわからないなと感じた方は公式ドキュメントを読むことをおすすめします。

まだ実際の案件で使っていないので、不具合などあれば随時更新していこうと思います。(おかしなところがあればご指摘いただけるとありがたいです)

最後までお読みいただきありがとうございました。

この記事が気に入ったらサポートをしてみませんか?