• 最終更新日:

gulp4の設定方法 - SassやAutoprefixer、ejs、画像の圧縮などを自動化する

gulp4の設定方法

gulpとはnode.jsベースで動くパッケージで、いままで面倒だった作業を自動化してくれる優れもの。今回gulp4で設定する内容は以下になります。

  • Sass(expandedとcompressedを選択可)
  • compressedときはcssを1行にする
  • autoprefixer(grid対応も)
  • htmlの共通部分のパーツ化(ejs)
  • 画像の圧縮
  • scriptの結合と圧縮(順番通りに結合してminify)
  • 開発と本番で処理を分岐
  • sourcemapの作成と削除

説明する環境は以下の通りです。

  • macOS Mojar v10.14.6
  • Visual Studio Code v1.39.2

gulp4に必要なパッケージを確認する

gulp4の設定を説明する前に、必要なパッケージがインストールできているか確認しましょう。必要なパッケージは3つ。

・Homebrew
・nodebrew
・node.js

gulpを使うにはまずnode.jsが必要になります。node.jsで使うgulpのようなパッケージはnpmで管理されますが、npmはnode.jsをインストールすると自動で付いてきます。
node.jsのバージョンによっては動かないパッケージがあるのでnode.jsのバージョンを自由に切り替えられるnodebrewが必要になります。Macにパッケージをバラバラにインストールすると管理が大変。そこでMacでインストールしたパッケージを一括して管理するためにhomebrewが必要になる、ということです。

このように管理する場所を明確にすることで、パッケージのインストール、バージョンアップや切り替えなどがスムーズに行えるようになります。

これらのHomebrew、nodebrew、node.jsをインストールする流れは以下の記事を参考にしてみてください。

Qiita | MacにNode.jsをインストール

gulp4の設定をする

まずは「gulp-model」というフォルダを作って、その中に必要はファイルやフォルダを作っていくことにします。ワークツリーのイメージは以下。「about」や「project」はデモページ用に作成しました。

 

package.jsonを準備する

まずはターミナルを使ってpackage.jsonを作ります。VScodeを使っている場合は、【 control + shift + @ 】でターミナルを開いて、以下のコマンドを打ちましょう。

npm init -y

 

gulp4をインストールする

ローカルとグローバルの両方にインストールする方法を見かけますが、バージョン違いでエラーになることもあるので、ローカルのみにインストールします。

npm install -D gulp

 

gulp4で使うパッケージをインストールする

gulpに本体をインストールできたら、自動化に必要はパッケージをインストールしていきます。以下のコマンドを必ず1行ずつコピーして実行してください。

npm i gulp -D gulp-sass # Sassを使う
npm i gulp -D gulp-postcss # Autoprefixと一緒に使うもの
npm i gulp -D autoprefixer # Autoprefix
npm i gulp -D gulp-plumber # エラーでも強制終了させない
npm i gulp -D gulp-notify # エラーのときはデスクトップに通知
npm i gulp -D gulp-htmlmin # htmlの圧縮・整理
npm i gulp -D del # ファイル、ディレクトリの削除
npm i gulp -D gulp-ejs # htmlのパーツ化
npm i gulp -D gulp-concat # ファイルの結合
npm i gulp -D gulp-order # 指定した順番で並べる
npm i gulp -D gulp-rename # ejsの拡張子を変更
npm i gulp -D gulp-clean-css # cssの圧縮
npm i gulp -D imagemin-pngquant # 画像圧縮
npm i gulp -D gulp-imagemin # 上と同じ
npm i gulp -D imagemin-mozjpeg # 上と同じ
npm i gulp -D gulp-uglify # script圧縮用
npm i gulp -D browser-sync # ブザウザ読み込み・反映
npm i gulp -D gulp-replace # 余計なテキストを削除
npm i gulp -D gulp-mode # 開発と本番の処理を分ける

 

まとめてインストールしたい方は半角スペースをあけて繋げて書くこともできます。

npm i gulp -D gulp-sass gulp-postcss autoprefixer gulp-plumber gulp-notifynpm i gulp -D gulp-htmlmin del gulp-ejs gulp-concat gulp-order gulp-rename gulp-clean-css imagemin-pngquant gulp-imagemin imagemin-mozjpeg gulp-uglify browser-sync gulp-replace gulp-mode

 

 

パッケージがインストールできると、package.jsonにパッケージ名が載っているので確認してみましょう。

 

gulpfile.jsに自動化処理を書く

gulpfile.jsを作成します。これはターミナルを使わず、通常のファイルを作成する方法と同じです。

gulpfile.jsには以下の内容を書いています。

//gulpとgulpのパッケージを読み込み
const { src, dest, watch, lastRun, parallel, series } = require("gulp");
const sass = require("gulp-sass");
const postcss = require("gulp-postcss");
const autoprefixer = require("autoprefixer");
const plumber = require("gulp-plumber");
const notify = require("gulp-notify");
const htmlmin = require("gulp-htmlmin");
const del = require("del");
const ejs = require("gulp-ejs");
const concat = require("gulp-concat");
const order = require("gulp-order");
const rename = require("gulp-rename");
const cleanCSS = require("gulp-clean-css");
const pngquant = require("imagemin-pngquant");
const imagemin = require("gulp-imagemin");
const mozjpeg = require("imagemin-mozjpeg");
const uglify = require("gulp-uglify");
const browserSync = require("browser-sync");
const replace = require("gulp-replace");

//開発と本番で処理を分ける
//今回はhtmlの処理のところで使っています
const mode = require("gulp-mode")({
  modes: ["production", "development"],
  default: "development",
  verbose: false
});

//読み込むパスと出力するパスを指定
const srcPath = {
  html: {
    src: ["./ejs/**/*.ejs", "!" + "./ejs/**/_*.ejs"],
    dist: "./"
  },
  styles: {
    src: "./src/scss/**/*.scss",
    dist: "./dist/css/",
    map: "./dist/css/map"
  },
  scripts: {
    src: "./src/js/**/*.js",
    dist: "./dist/js/",
    map: "./dist/js/map",
    core: "src/js/core/**/*.js",
    app: "src/js/app/**/*.js"
  },
  images: {
    src: "./src/img/**/*.{jpg,jpeg,png,gif,svg}",
    dist: "./dist/img/"
  }
};

//htmlの処理自動化
const htmlFunc = () => {
  return src(srcPath.html.src)
    .pipe(
      plumber({ errorHandler: notify.onError("Error: <%= error.message %>") })
    )
    .pipe(ejs({}, {}, { ext: ".html" })) //ejsを纏める
    .pipe(rename({ extname: ".html" })) //拡張子をhtmlに

    .pipe(
      mode.production(
        //本番環境のみ
        htmlmin({
          //htmlの圧縮
          collapseWhitespace: true, // 余白を除去する
          preserveLineBreaks: true, //改行を詰める
          minifyJS: true, // jsの圧縮
          removeComments: true // HTMLコメントを除去する
        })
      )
    )
    .pipe(replace(/[\s\S]*?(<!DOCTYPE)/, "$1"))
    .pipe(dest(srcPath.html.dist))
    .pipe(browserSync.reload({ stream: true }));
};

//Sassの処理自動化(開発用)
const stylesFunc = () => {
  return src(srcPath.styles.src, { sourcemaps: true })
    .pipe(
      plumber({ errorHandler: notify.onError("Error: <%= error.message %>") })
    )
    .pipe(sass({ outputStyle: "expanded" }).on("error", sass.logError))
    .pipe(
      postcss([
        autoprefixer({
          // IEは11以上、Androidは4、ios safariは8以上
          // その他は最新2バージョンで必要なベンダープレフィックスを付与する
          //指定の内容はpackage.jsonに記入している
          cascade: false,
          grid: true
        })
      ])
    )
    .pipe(dest(srcPath.styles.dist, { sourcemaps: "./map" }))
    .pipe(browserSync.reload({ stream: true }));
};

//Sassの処理自動化(本番用)
const stylesCompress = () => {
  return src(srcPath.styles.src)
    .pipe(
      plumber({ errorHandler: notify.onError("Error: <%= error.message %>") })
    )
    .pipe(sass({ outputStyle: "compressed" }).on("error", sass.logError))
    .pipe(
      postcss([
        autoprefixer({
          //上の指定と同じ
          cascade: false,
          grid: true
        })
      ])
    )
    .pipe(cleanCSS())
    .pipe(dest(srcPath.styles.dist))
    .pipe(browserSync.reload({ stream: true }));
};

//scriptの処理自動化
const scriptFunc = () => {
  return src(srcPath.scripts.src, { sourcemaps: true })
    .pipe(order([srcPath.scripts.core, srcPath.scripts.app], { base: "./" }))
    .pipe(
      plumber({ errorHandler: notify.onError("Error: <%= error.message %>") })
    )
    .pipe(concat("init.js"))
    .pipe(uglify({ output: { comments: /^!/ } }))
    .pipe(
      rename({
        suffix: ".min"
      })
    )
    .pipe(dest(srcPath.scripts.dist, { sourcemaps: "./map" }))
    .pipe(browserSync.reload({ stream: true }));
};

//画像圧縮の定義
const imagesBase = [
  pngquant({
    quality: [0.7, 0.85]
  }),
  mozjpeg({
    quality: 85
  }),
  imagemin.gifsicle(),
  imagemin.jpegtran(),
  imagemin.optipng(),
  imagemin.svgo({
    removeViewBox: false
  })
];

//画像の処理自動化
const imagesFunc = () => {
  return src(srcPath.images.src, { since: lastRun(imagesFunc) })
    .pipe(plumber({ errorHandler: notify.onError("<%= error.message %>") }))
    .pipe(imagemin(imagesBase))
    .pipe(dest(srcPath.images.dist));
};

// マップファイル除去
const cleanMap = () => {
  return del([srcPath.styles.map, srcPath.scripts.map]);
};

// ブラウザの読み込み処理
const browserSyncFunc = () => {
  browserSync({
    server: {
      baseDir: "./",
      index: "index.html"
    },
    reloadOnRestart: true
  });
};

// ファイルに変更があったら反映
const watchFiles = () => {
  watch(srcPath.html.src, htmlFunc);
  watch(srcPath.styles.src, stylesFunc);
  watch(srcPath.scripts.src, scriptFunc);
  watch(srcPath.images.src, imagesFunc);
};

exports.default = parallel(watchFiles, browserSyncFunc); //gulpの初期処理
exports.build = parallel(htmlFunc, stylesFunc, scriptFunc, imagesFunc);

exports.sasscompress = stylesCompress;
exports.cleanmap = cleanMap;

 

Autoprefixerの指定を書く

Autoprefixerの指定をpackage.jsonに加えます。今回の指定は以下のようにしています。

  • ie11以上
  • Android4以上
  • ios safari8以上
  • その他は最新の2バージョンに対してベンダープレフィックスをつける

package.jsonを開いて以下を追記します。

"browserslist": [
    "last 2 versions",
    "ie >= 11",
    "Android >= 4",
    "ios_saf >= 8"
  ]

 

 

gulpfile.jsの中身を説明

gulpfile.jsに書いた内容を簡単に説明していきます。

読み込むパスと出力するパスを指定

gulpで自動化する上で、処理前にどのフォルダからファイルを読み込むか、処理後に出力されるファイルをどこのフォルダへ出力するか指定する必要があります。

例えばcssの処理するパスは以下のように設定しています。srcの部分は、処理前のファイルパスを、distの部分は処理後に出力するフォルダまでのパスを、mapの部分にはsourcemapを出力するフォルダまでのパスを示しています。

styles: {
    src: "./src/scss/**/*.scss", // ここから読み込んで
    dist: "./dist/css/", // ここに出力する
    map: "./dist/css/map" //sourcemapはここに出力する
  }

 

ワークツリーで見るとこんな感じになります。

 

htmlの処理自動化

headerやfooterなど各ページで共通部分があればejsを使ってパーツ化することができます。それぞれのページと共通部分をejsの拡張子で作成。そのあとに拡張子をhtmlに変更して、それぞれのフォルダに出力させる処理をしています。

細かい設定については、はにわまんさんの記事が参考にしてみてください。

EJSの使い方!静的なHTMLサイトで「共通パーツ」と「変数」を使おう | HP code

ワークツリーでは以下のようになります。

 

htmlの自動化では開発環境と本番環境で処理を分けています。
本番環境に出力するコマンドを打つと、html上にあったコメントや上下の隙間を消しています。1行に圧縮していませんが、インデントが無くなるためコードがすべて左寄りになります。使う場合は以下のコマンドを打ちます。

npx gulp --production

 

Sassの処理自動化

通常はexpandedでcssへ出力し、soucemapも作成する設定をしています。本番環境への出力のときは、compressedで出力して1行にまとめます。そのときはsoucemapは出力させません。

本番環境への出力のときは以下のコマンドを打ちます。

npx gulp sasscompress

 

scriptの処理自動化

scriptの自動化処理では、最初にjQuery本体、その次にプラグイン、最後に自分で設定を書いているinit.jsの順番で結合してから圧縮させています。この圧縮処理をするとプラグインのライセンス情報が消えてしまうため、jQuery本体のほうに追記しておく必要があります。

こんな感じになります。

 

処理前のファイルはcoreにjQuery本体、appにプラグイン、js直下に自分で書く用のinit.jsを置きます。

 

画像の自動処理化

jpgやpng、gif、svgの圧縮処理をします。lastRunによってwatchから2回目以降はアップロードした画像のみ圧縮処理をしてくれます。(1回目は毎回全画像を圧縮処理)

ファイルや画像が更新されたら自動で反映させる

以下の部分は更新されたファイルや画像をチェックして、先に設定しておいた自動化処理を反映させるための設定です。watchすることでファイルが保存された瞬間に自動化処理が実行されます。

// ファイルに変更があったら反映
const watchFiles = () => {
  watch(srcPath.html.src, htmlFunc); // ejsファイルに変更があったら…
  watch(srcPath.styles.src, stylesFunc); // sassファイルに変更があったら… 
  watch(srcPath.scripts.src, scriptFunc); // scriptに変更があったら…
  watch(srcPath.images.src, imagesFunc); // 画像をアップロードしたら…
};

 

自動化処理を実行する

自動化処理のための定義を書いていたので、実際に定義した内容を実行するには以下のコマンドが必要になります。
グローバルにgulpをインストールしていないので、実行するコマンドに注意しましょう。

npx gulp

 

このコマンドによって、htmlとcss、script、画像の処理、ブラウザへの反映をまとめてやってくれます。コマンドを打ったあとはファイルを保存するだけで自動で反映されます。

ブラウザに表示させず、全体のファイルを更新するだけなら以下です。

npx gulp build

 

 

本番環境用に出力するなら以下。本番環境用の出力では、htmlのコメントや余計は上下の隙間を無くす処理を設定しています。

npx gulp --production

 

 

以下のコマンドはSassで出力したcssを圧縮する処理をします。これも本番環境用に最後に実行するコマンドです。

npx gulp sasscompress

 

 

以下はsourcemapを削除するコマンドです。本番環境に移すときに使います。

npx gulp cleanmap

 

gulp4の設定を他のプロジェクトでも使うには?

まずは設定済みのgulpfile.jsとpackage.jsonをコピーして他のプロジェクトのフォルダへ移しましょう。移せたら以下のコマンドを実行します。

npm install -D

 

これでpackage.jsonに書かれたパッケージがインストールされるので、gulpfile.jsがあれば同じ設定で使うことができます。

インストールしたら念のために以下のコマンドを打ってpackage.jsonに書かれたパッケージが正しくインストールできているか確認しましょう。

npm ls --depth=0

 

gitではnode_modulesを除外する

node_modulesはnpmでインストールしたパッケージを保管する場所。package.jsonと同じ階層に作成されます。ただgitで管理するには重く、また特にnode_modulesがなくてもgulpfile.jsとpackage.jsonがあれば同じ環境を構築することができるので、gitの管理から外しておきます。

.gitignoreという名前のファイルを作成して、以下の内容を書きます。*のワイルドカードをつけることでどの階層にあってもnode_modulesを除外することができます。

#node_modulesを除外する
*node_modules/

 

まとめと参照サイト

今回はgulp4の設定方法を説明しました。プロジェクトに合わせて設定内容を調整してみてください。今回の設定をするにあたって多くのサイトを参考させてもらいました。特に勉強になったサイトを載せておきます。