見出し画像

【gulp4】もう迷わないgulpfile.jsの書き方


gulpとは、Node.jsで動作するビルドシステムヘルパーと言って、web制作において時間のかかるタスクを自動化できる便利なツールです。

gulpを使うことで様々な処理を自動で行うことができ、とっても便利なのです。


さて、

gulpは前から使っていたのですが、gulpfile.jsの書き方が非推奨となっていたため、一から書き直してみました。


Node.jsの説明やgulpの環境構築についてはこの記事では触れません。

環境構築から知りたい方は、ICS MEDIAさんの記事がおすすめです。


今回追加する処理

・Sassのコンパイル、圧縮
・JavaScriptのトランスパイル、圧縮
・画像圧縮
・ブラウザ自動リロード
・(おまけ)FTPアップロード


「gulp 環境構築」「gulp sass コンパイル」などでググっても、taskを使った非推奨の書き方が多いです。

この書き方でも動くのですが、後々バグが起きそうだし、今のうちにちゃんと書いておきたい。


という訳で、一番信頼できる公式サイトを参考にします。


ちょっとわからない部分は、DeepLに助けてもらいました。(翻訳の精度高いので使える!)


ディレクトリ構造

ディレクトリ構造はこんな感じです。

srcが作業ディレクトリで、コンパイル前のscssファイルや圧縮前のjsファイル、画像ファイルが格納されています。

gulpが走ると、distディレクトリにコンパイルされます。

├─ index.html
├─ gulpfile.js
├─ package.json
├─ package.look.json
├─ /node_modules
├─ /dist
│  ├─ /css
│  │  └─ style.css
│  ├─ /js
│  │  └─ script.js
│  └─ /img
└─ /src
   ├─ /scss
   │  └─ style.scss
   ├─ /js
   │  └─ script.js
   └─ /img


npmパッケージについての説明は割愛しますが、progateで解説されている記事があったので紹介しておきますね。


基本的なgulpfile.jsの書き方

テキストエディタを使って、プロジェクトのルートにgulpfile.jsという名前のファイルを作成し、以下の内容で作成します。


/*
src 参照元を指定
dest 出力さきを指定
watch ファイル監視
series(直列処理)とparallel(並列処理)
*/
const { src, dest, watch, series, parallel } = require('gulp');

// プラグインを呼び出し
const sass = require('gulp-sass');

// プラグインの処理をまとめる
const cssSass = () => {
 return src('src/css/**/*.scss') //コンパイル元
   .pipe(sass({ outputStyle: 'expanded' }))
   .pipe(dest('dist/css'))     //コンパイル先
}

// タスクをまとめて実行
exports.default = series(cssSass);


基本的な書き方を覚えておけば、あとは公式のドキュメントを見ながら書いていけると思います。

それでは順番に解説していきます。

/*
src 参照元を指定
dest 出力さきを指定
watch ファイル監視
series(直列処理)とparallel(並列処理)
*/
const { src, dest, watch, series, parallel } = require('gulp');

まず、gulpで使うことのできるメソッドを呼び出します。

src 参照元を指定
dest 出力先を指定
watch ファイル監視
series(直列処理)とparallel(並列処理)

src('src/css/**/*.scss')としてコンパイルする参照元を指定したり、

dest('dist/css')として出力先のディレクトリを指定する時に使いますね。


この辺りの詳しい説明は、公式ドキュメントを参照してください。

→ Working with Files


npm installしたプラグインを requireで呼び出し、あとで処理をまとめるために変数に代入します。

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



// プラグインの処理をまとめる
const cssSass = () => {
 return src('src/css/**/*.scss') //コンパイル元
   .pipe(sass({ outputStyle: 'expanded' }))
   .pipe(dest('dist/css'))     //コンパイル先
}

// タスクをまとめて実行
exports.default = series(cssSass);

ここで、新たにプラグインの処理を記述した関数を定義して、オプションの内容を書いていきます。

基本的には、returnのあと.pipe()でつなげて書いていけばいいみたいですね。


pipeメソッドについて

pipeメソッドは、引数に関数をとって、その関数にストリームを渡す。

gulpに読み込まれたscssファイルは、Node.jsで処理するためのデータ形式(ストリーム)に変換されています。
先ほど出てきたsrcメソッドを使うことで、「ファイルパスを受け取って読み込み、ストリームに変換する」という処理が行われています。

ちょっとややこしく感じるかもしれませんが、「returnで実行する時、pipeメソッドで色々な処理を追加していく」と考えていいと思います。


この例だと、以下の内容を記述していて、これらをpipeで繋ぎます。

コンパイル元のディレクトリ指定
コンパイルオプション(outputStyle:expanded)
コンパイル先のディレクトリ指定


こちらですが、
プラグインの公式ドキュメントの書き方を参考にしてます。


Sassのコンパイル

さて、基本の書き方がわかったところで、まずは一気にSassのコンパイル部分を書いていきましょう。


gulpfile.jsを一気に書いて、プラグインもまとめてインストールすればいいのですが、ここでは一つずつ解説していきます。

ちなみに、一度gulpfile.jsやpackage.jsonの設定をしてしまえば、
他の案件で使う時には、gulpfile.jsとpackage.jsonのみコピーし、「npm install」とするだけで必要なプラグインがまとめてインストールされます。


まずはプラグインをインストールするところからです。個人的に最低限必要だと思うのはこちら。

インストールするプラグイン

gulp-sass
gulp-plumber
gulp-notify
gulp-postcss
postcss-cssnext
gulp-clean-css
gulp-rename
gulp-sourcemaps
css-mqpacker

上記リンク先はnpmにしています。


まとめてインストールするコマンド

npm install --save-dev gulp gulp-sass gulp-sourcemaps gulp-notify gulp-plumber gulp-postcss postcss-cssnext gulp-clean-css gulp-rename css-mqpacker


どんな設定にするかはその人次第、案件次第になってくるので、ドキュメントを見つつ、いろんなパターンを作ってみるのもいいかもですね。

/*
src 参照元を指定
dest 出力さきを指定
watch ファイル監視
series(直列処理)とparallel(並列処理)
*/
const { src, dest, watch, series, parallel } = require('gulp');

//scss
const sass = require('gulp-sass');
const plumber = require("gulp-plumber");    // エラーが発生しても強制終了させない
const notify = require("gulp-notify");      // エラー発生時のアラート出力
const postcss = require("gulp-postcss");    // PostCSS利用
const cssnext = require("postcss-cssnext")  // CSSNext利用
const cleanCSS = require("gulp-clean-css"); // 圧縮
const rename = require("gulp-rename");      // ファイル名変更
const sourcemaps = require("gulp-sourcemaps");  // ソースマップ作成
const mqpacker = require('css-mqpacker');     //メディアクエリをまとめる

//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
 'last 2 versions',
 '> 5%',
 'ie = 11',
 'not ie <= 10',
 'ios >= 8',
 'and_chr >= 5',
 'Android >= 5',
]

//参照元パス
const srcPath = {
 css: 'src/scss/**/**.scss',
}

//出力先パス
const destPath = {
 css: 'dist/css/',
}

//sass
const cssSass = () => {
 return src(srcPath.css) //コンパイル元
   .pipe(sourcemaps.init())//gulp-sourcemapsを初期化
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error:<%= error.message %>')
         //エラー出力設定
       }
     )
   )
   .pipe(sass({ outputStyle: 'expanded' }))
   .pipe(postcss([mqpacker()])) // メディアクエリを圧縮
   .pipe(postcss([cssnext(browsers)]))//cssnext
   .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
   .pipe(dest(destPath.css))         //コンパイル先
   .pipe(cleanCSS()) // CSS圧縮
   .pipe(
     rename({
       extname: '.min.css' //.min.cssの拡張子にする
     })
 )
}

//処理をまとめて実行
exports.default = series(cssSass);

書き方は、前述した基本の書き方と何ら変わりはありませんが、定数で管理した方が良さそうなところは、予め宣言しておきます。

例えば、参照元パスと出力先パスやpostcss-cssnextのオプションに記述するブラウザ対応条件など、予め書いておくと後々変更するのも簡単です。

パスの部分は、jsや画像もあとで追加します。


プラグインの書き方ですが、pipeで繋ぎつつ、オプションで指定する項目があれば書いてあげます。オプションの書き方はドキュメントを見ればサンプルがあるはずです。​


ここまでできたら、scssファイルを適当に書いて、ターミナルでgulpと書いて実行してみましょう。

gulp

おそらく、コンパイルが成功するはず。


JavaScriptのトランスパイル&圧縮

Web制作だとjQueryが中心になるので、ネイティブなJavaScriptを書くことはあまりないかもしれません。

が案件で使うこともあったので、一応触れておきます。


ES2015以降の構文はブラウザーによっては対応していないこともあるため、BabelなどでES5相当のコードに変換します。

これをトランスパイルと言います。


主にIEですね。。


インストールするプラグイン

@babel/core
@babel/preset-env
gulp-babel
gulp-uglify
npm install --save-dev @babel/core @babel/preset-env gulp-babel gulp-uglify


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

//scss
const sass = require('gulp-sass');
const plumber = require("gulp-plumber");    // エラーが発生しても強制終了させない
const notify = require("gulp-notify");      // エラー発生時のアラート出力
const postcss = require("gulp-postcss");    // PostCSS利用
const cssnext = require("postcss-cssnext")  // CSSNext利用
const cleanCSS = require("gulp-clean-css"); // 圧縮
const rename = require("gulp-rename");      // ファイル名変更
const sourcemaps = require("gulp-sourcemaps");  // ソースマップ作成
const mqpacker = require('css-mqpacker');     //メディアクエリをまとめる

//js babel
const babel = require("gulp-babel");
const uglify = require("gulp-uglify");


//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
 'last 2 versions',
 '> 5%',
 'ie = 11',
 'not ie <= 10',
 'ios >= 8',
 'and_chr >= 5',
 'Android >= 5',
]

//参照元パス
const srcPath = {
 css: 'src/scss/**/**.scss',
 js: 'src/js/*.js',
}

//出力先パス
const destPath = {
 css: 'dist/css/',
 js: 'dist/js/',
}


//sass
const cssSass = () => {
 return src(srcPath.css) //コンパイル元
   .pipe(sourcemaps.init())//gulp-sourcemapsを初期化
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error:<%= error.message %>')
         //エラー出力設定
       }
     )
   )
   .pipe(sass({ outputStyle: 'expanded' }))
   .pipe(postcss([mqpacker()])) // メディアクエリを圧縮
   .pipe(postcss([cssnext(browsers)]))//cssnext
   .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
   .pipe(dest(destPath.css))         //コンパイル先
   .pipe(cleanCSS()) // CSS圧縮
   .pipe(
     rename({
       extname: '.min.css' //.min.cssの拡張子にする
     })
 )
}


// babelのトランスパイル、jsの圧縮
const jsBabel = () => {
 return src(srcPath.js)
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error: <%= error.message %>')
       }
     )
   )
   .pipe(babel({
     presets: ['@babel/preset-env']  // gulp-babelでトランスパイル
   }))
   .pipe(dest(destPath.js))
   .pipe(uglify()) // js圧縮
   .pipe(
     rename(
       { extname: '.min.js' }
     )
   )
   .pipe(dest(destPath.js))
}

exports.default = series(cssSass, jsBabel);

ざっとこんな感じです。

あまり使わないもので、ほとんどgulp-babelのドキュメント通りです。。



 これで例えば、/src/js/index.jsにES6の構文で書いてみましょう。

// アロー関数のテスト
const hoge = (name) => {
 console.log(name);
};
hoge('taro');


gulpを走らせてみましょう。​​


"use strict";

// アロー関数のテスト
var hoge = function hoge(name) {
 console.log(name);
};

hoge('taro');

すると、こんな感じでES5に対応したコードに変換されました、成功です。

こんな感じで、babelもサクッと実装できます。


画像圧縮

サイトの通信容量に負担をかけやすいのが画像ですよね。サイトの表示速度はSEO的にもユーザビリティ的にも優先度は高めで、そのための画像圧縮はWeb制作業務では当たり前になってます。

今時、画像圧縮を手作業でやるのもちょっとあれなので、gulpで自動化しましょう。


インストールするプラグイン

gulp-imagemin
imagemin-mozjpeg
imagemin-pngquant
imagemin-svgo
npm install --save-dev gulp-imagemin imagemin-mozjpeg imagemin-pngquant imagemin-svgo



ん、、?


gulp-imageminのReadmeを読んだら、こう書いてある。

「Minify PNG, JPEG, GIF and SVG images with imagemin」
(imagemin で PNG、JPEG、GIF、SVG 画像を最小化する)

imagemin-mozjpeg、imagemin-pngquant、imagemin-svgoこの3つはjpeg、png、svgだから被ってない??


そう思った方はカンがいいです。実は「圧縮方法」が違うのです。

gulp-imagemin → ロスレス圧縮
imagemin-mozjpeg → 不可逆圧縮
imagemin-pngquant → 不可逆圧縮
imagemin-svgo → 不可逆圧縮


ロスレス圧縮
圧縮前と圧縮後でデータを損なわない圧縮方法
画像表示に関わらない情報を削除するだけなので、画像の質が落ちないが、ほとんど軽量化できない。
画像情報の他に透明度やガンマ値、文字情報があるpngやsvgなら少しは容量は減らせる。

不可逆圧縮
画像の色を減らすなど、高性能なアルゴリズムで「適切に色情報を減らすことで画質を保ちつつ大幅な圧縮ができる。」


mozjpegやpngquant、svgoはgulp-imageminで不可逆圧縮を行うためのプラグインです。


gulpfile.jsはこんな感じになります。

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

//scss
const sass = require('gulp-sass');
const plumber = require("gulp-plumber");    // エラーが発生しても強制終了させない
const notify = require("gulp-notify");      // エラー発生時のアラート出力
const postcss = require("gulp-postcss");    // PostCSS利用
const cssnext = require("postcss-cssnext")  // CSSNext利用
const cleanCSS = require("gulp-clean-css"); // 圧縮
const rename = require("gulp-rename");      // ファイル名変更
const sourcemaps = require("gulp-sourcemaps");  // ソースマップ作成
const mqpacker = require('css-mqpacker');     //メディアクエリをまとめる

//js babel
const babel = require("gulp-babel");
const uglify = require("gulp-uglify");

//画像圧縮
const imagemin = require("gulp-imagemin");
const imageminMozjpeg = require("imagemin-mozjpeg");
const imageminPngquant = require("imagemin-pngquant");
const imageminSvgo = require("imagemin-svgo");


//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
 'last 2 versions',
 '> 5%',
 'ie = 11',
 'not ie <= 10',
 'ios >= 8',
 'and_chr >= 5',
 'Android >= 5',
]

//参照元パス
const srcPath = {
 css: 'src/scss/**/**.scss',
 js: 'src/js/*.js',
 img: 'src/img/**/*',
}

//出力先パス
const destPath = {
 css: 'dist/css/',
 js: 'dist/js/',
 img: 'dist/img/'
}


//sass
const cssSass = () => {
 return src(srcPath.css) //コンパイル元
   .pipe(sourcemaps.init())//gulp-sourcemapsを初期化
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error:<%= error.message %>')
         //エラー出力設定
       }
     )
   )
   .pipe(sass({ outputStyle: 'expanded' }))
   .pipe(postcss([mqpacker()])) // メディアクエリを圧縮
   .pipe(postcss([cssnext(browsers)]))//cssnext
   .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
   .pipe(dest(destPath.css))         //コンパイル先
   .pipe(cleanCSS()) // CSS圧縮
   .pipe(
     rename({
       extname: '.min.css' //.min.cssの拡張子にする
     })
 )
}


// babelのトランスパイル、jsの圧縮
const jsBabel = () => {
 return src(srcPath.js)
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error: <%= error.message %>')
       }
     )
   )
   .pipe(babel({
     presets: ['@babel/preset-env']  // gulp-babelでトランスパイル
   }))
   .pipe(dest(destPath.js))
   .pipe(uglify()) // js圧縮
   .pipe(
     rename(
       { extname: '.min.js' }
     )
   )
   .pipe(dest(destPath.js))
}

//画像圧縮(デフォルトの設定)
const imgImagemin = () => {
 return src(srcPath.img)
   .pipe(
     imagemin(
       [
         imageminMozjpeg({
           quality: 80
         }),
         imageminPngquant(),
         imageminSvgo({
           plugins: [
             {
               removeViewbox: false
             }
           ]
         })
       ],
       {
         verbose: true
       }
     )
   )
   .pipe(dest(destPath.img))
}

exports.default = series(cssSass, jsBabel, imgImagemin);


src/imgに画像を入れて、gulpで実行してみてください。圧縮されて、/distディレクトリに出力されたはずです。


ファイル監視、ブラウザ自動リロード

さて、これまでsassのコンパイル、jsトランスパイル、画像圧縮の設定を書いてきましたが、現状だと毎回ターミナルでgulpと入力しないといけないです。

今度は、ファイルの変更を監視し、自動で処理を実行する処理を書いていきましょう。

ついでに、ブラウザを自動でリロードしてくれたら助かりますね。


インストールするプラグイン

browser-sync
npm install --save-dev browser-sync


もう書き方には慣れてきたはず。


//ブラウザリロード
const browserSync = require("browser-sync");

プラグインを読み込んで、



//ローカルサーバー立ち上げ、ファイル監視と自動リロード
const browserSyncFunc = () => {
 browserSync.init(browserSyncOption);
}

const browserSyncOption = {
 proxy: 'http://localhost/',       //環境によって変更する
 open: true,
 reloadOnRestart: true,
}

//リロード
const browserSyncReload = (done) => {
 browserSync.reload();
 done();
}

//ファイル監視
const watchFiles = () => {
 watch(srcPath.css, series(cssSass, browserSyncReload))
 watch(srcPath.js, series(jsBabel, browserSyncReload))
 watch(srcPath.img, series(imgImagemin, browserSyncReload))
}

オプションを書いていきます。

結構長いですが、そんなに難しくありません。


//ローカルサーバー立ち上げ
const browserSyncFunc = () => {
 browserSync.init(browserSyncOption);
}

コールバック関数内にローカルサーバーを起動するための操作を書きます。

initメソッドは、起動コマンドです。「browserSyncOption」のオプションでローカルサーバーを起動してねという意味ですね。


const browserSyncOption = {
 proxy: 'http://localhost/',       //環境によって変更する
 open: true,
 reloadOnRestart: true,
}

initメソッドのオプションを定義します。proxyはローカルホストのドキュメントルートを指定しておけばいいかと思います。

ここで指定したURLを元に、http://localhost:3000といったローカルサーバーが立ち上がります。


//リロード
const browserSyncReload = (done) => {
 browserSync.reload();
 done();
}

reloadメソッドを呼び出して、ブラウザを更新します。ただ、これだけだと関数を定義しただけですね。


//ファイル監視
const watchFiles = () => {
 watch(srcPath.css, series(cssSass, browserSyncReload))
 watch(srcPath.js, series(jsBabel, browserSyncReload))
 watch(srcPath.img, series(imgImagemin, browserSyncReload))
}

gulpのwatchメソッドと組み合わせて、「ファイルの変更を検知したら、reloadメソッドを呼び出す」ようにしましょう。

seriesメソッドは、「順番に実行してね!」という意味です。


つまり、

srcPathを監視
→ファイルに変更があればcssSassを実行してからリロードしてね


ちなみに、Watchメソッドはこのように書きます。

watch('監視するファイル',処理)



これまでに「参照元パス」を定義してきましたので、それを使いましょう。

//参照元パス
const srcPath = {
 css: 'src/scss/**/**.scss',
 js: 'src/js/*.js',
 img: 'src/img/**/*',
 html: './**/*.html', 
 php: './**/*.php',
}

htmlとphpを変更した時にもリロードしたいので、パスを追加し、watchにも追加しておきました。


//ファイル監視
const watchFiles = () => {
 watch(srcPath.css, series(cssSass, browserSyncReload))
 watch(srcPath.js, series(jsBabel, browserSyncReload))
 watch(srcPath.img, series(imgImagemin, browserSyncReload))
 watch(srcPath.html, series(browserSyncReload))
 watch(srcPath.php, series(browserSyncReload))
}



exports.default = series(series(cssSass, jsBabel, imgImagemin), parallel(watchFiles, browserSyncFunc));

そして、最後のコード部分には、parallelメソッドでwatchFilesとbrowserSyncFuncを実行します。

seriesは「順番」に実行
parallelは並列で実行

watchやローカルサーバー起動などのタスクは、裏で実行されている必要があるためparallelで囲い、全体はseriesで囲って実行します。


これでいい感じですね。


ちなみに、gulpを実行するとターミナルではこんな表示になります。

[02:30:02] Starting 'watchFiles'...
[02:30:02] Starting 'browserSyncFunc'...
[Browsersync] Proxying: http://localhost
[Browsersync] Access URLs:
-------------------------------------
      Local: http://localhost:3007
   External: http://192.168.11.7:3007
-------------------------------------
         UI: http://localhost:3008
UI External: http://localhost:3008
-------------------------------------

LocalのURLがブラウザで自動的に開かれます。

「External」と表示のあるURLを使えば、同一ネットワークに存在する別の端末からアクセスすることができます。

例えば、スマホやタブレット、IE端末で検証する場合に便利です!

もちろん、PCでファイルを更新したら、スマホ側でも自動更新されます。


「UI」のURLにアクセスすると、下記のような画面が表示されます。

スクリーンショット 2020-05-09 2.41.19


これは、Browsersyncの動きを設定できる画面です。

例えば複数の端末から確認している場合、スクロールやクリックした場合の動きをミラーリングさせたり、端末間の検証作業が捗るので、個人的にはおすすめです。


まとめ


全体のコードはこんな感じです。

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

//scss
const sass = require('gulp-sass');
const plumber = require("gulp-plumber");    // エラーが発生しても強制終了させない
const notify = require("gulp-notify");      // エラー発生時のアラート出力
const postcss = require("gulp-postcss");    // PostCSS利用
const cssnext = require("postcss-cssnext")  // CSSNext利用
const cleanCSS = require("gulp-clean-css"); // 圧縮
const rename = require("gulp-rename");      // ファイル名変更
const sourcemaps = require("gulp-sourcemaps");  // ソースマップ作成
const mqpacker = require('css-mqpacker');     //メディアクエリをまとめる

//js babel
const babel = require("gulp-babel");
const uglify = require("gulp-uglify");

//画像圧縮
const imagemin = require("gulp-imagemin");
const imageminMozjpeg = require("imagemin-mozjpeg");
const imageminPngquant = require("imagemin-pngquant");
const imageminSvgo = require("imagemin-svgo");

//ファイル監視
const browserSync = require("browser-sync");


//postcss-cssnext ブラウザ対応条件 prefix 自動付与
const browsers = [
 'last 2 versions',
 '> 5%',
 'ie = 11',
 'not ie <= 10',
 'ios >= 8',
 'and_chr >= 5',
 'Android >= 5',
]

//参照元パス
const srcPath = {
 css: 'src/scss/**/**.scss',
 js: 'src/js/*.js',
 img: 'src/img/**/*',
 html: './**/*.html', 
 php: './**/*.php',
}

//出力先パス
const destPath = {
 css: 'dist/css/',
 js: 'dist/js/',
 img: 'dist/img/'
}


//sass
const cssSass = () => {
 return src(srcPath.css) //コンパイル元
   .pipe(sourcemaps.init())//gulp-sourcemapsを初期化
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error:<%= error.message %>')
         //エラー出力設定
       }
     )
   )
   .pipe(sass({ outputStyle: 'expanded' }))
   .pipe(postcss([mqpacker()])) // メディアクエリを圧縮
   .pipe(postcss([cssnext(browsers)]))//cssnext
   .pipe(sourcemaps.write('/maps'))  //ソースマップの出力
   .pipe(dest(destPath.css))         //コンパイル先
   .pipe(cleanCSS()) // CSS圧縮
   .pipe(
     rename({
       extname: '.min.css' //.min.cssの拡張子にする
     })
 )
}


// babelのトランスパイル、jsの圧縮
const jsBabel = () => {
 return src(srcPath.js)
   .pipe(
     plumber(              //エラーが出ても処理を止めない
       {
         errorHandler: notify.onError('Error: <%= error.message %>')
       }
     )
   )
   .pipe(babel({
     presets: ['@babel/preset-env']  // gulp-babelでトランスパイル
   }))
   .pipe(dest(destPath.js))
   .pipe(uglify()) // js圧縮
   .pipe(
     rename(
       { extname: '.min.js' }
     )
   )
   .pipe(dest(destPath.js))
}

//画像圧縮(デフォルトの設定)
const imgImagemin = () => {
 return src(srcPath.img)
   .pipe(
     imagemin(
       [
         imageminMozjpeg({
           quality: 80
         }),
         imageminPngquant(),
         imageminSvgo({
           plugins: [
             {
               removeViewbox: false
             }
           ]
         })
       ],
       {
         verbose: true
       }
     )
   )
   .pipe(dest(destPath.img))
}


//ローカルサーバー立ち上げ、ファイル監視と自動リロード
const browserSyncFunc = () => {
 browserSync.init(browserSyncOption);
}
const browserSyncOption = {
 proxy: 'http://localhost/',       //環境によって変更する
 open: true,
 reloadOnRestart: true,
}

//リロード
const browserSyncReload = (done) => {
 browserSync.reload();
 done();
}

//ファイル監視
const watchFiles = () => {
 watch(srcPath.css, series(cssSass, browserSyncReload))
 watch(srcPath.js, series(jsBabel, browserSyncReload))
 watch(srcPath.img, series(imgImagemin, browserSyncReload))
 watch(srcPath.html, series(browserSyncReload))
 watch(srcPath.php, series(browserSyncReload))
}

exports.default = series(series(cssSass, jsBabel, imgImagemin), parallel(watchFiles, browserSyncFunc));


今回のサンプルコードはGithubにあげてるので、参考にどうぞ。



(おまけ)FTPアップロード

const ftp = require("vinyl-ftp");


// アカウント情報の定義
const connect = ftp.create({
 host: 'ホスト名',
 user: 'アカウント名',
 password: 'パスワード',
})

// アップロードするファイルパス
const ftpUploadFiles = [
 'dist/**',
 'dist/css/**',
 'dist/js/**',
 'dist/img/**',
 'index.html'
]

// アップロード先ディレクトリパス
const remoteDistDir = '/'

const vinylFtp = () => {
 return src(ftpUploadFiles, { buffer: false })
 .pipe(connect.newerOrDifferentSize(remoteDistDir))
 .pipe(connect.dest(remoteDistDir))
}

exports.ftp = series(vinylFtp)


実行

gulp ftp


const vinylFtp = () => {
 return src(ftpUploadFiles, { buffer: false })
 .pipe(connect.newerOrDifferentSize(remoteDistDir))
 .pipe(connect.dest(remoteDistDir))
}

connect.newerOrDifferentSizeメソッドで、

サーバーのファイルと比較し、更新日が新しく、ファイル容量が変化したもののみをアップするようにしています。


ちなみに、以下のメソッドも使えます。

newer → 更新日時が新しいファイル
differentSize → ファイル容量が変化したファイル


FTPは個人的にしか使いませんが、「こんなこともできるんだー」くらいに思っておくといいかもしれません。


あとは、webpackを使ってライブラリを管理したり、EJSやpugを使ったり、できることはたくさんあるので、ドキュメントを読みつつまずはgulpfile.jsを書きまくって試してみてください。


少しでも参考になれば幸いです。


参考資料

今回参考にしたのは、こちらの公式ドキュメントと、「gulpで始めるWeb制作ワークフロー」という書籍です。





サポートいただければ嬉しいです。