6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【Gulp4対応】ほどよくこだわるgulpfile

Posted at

⚠︎Gulp4になって地味に記法が変わっていたので、本記事はちゃんとGulp4で推奨されている記法に沿って書いております!

静的ページをガリガリ書こう!とはいえ…

制作する上でたくさん処理がありますよね
sassのコンパイルから始まり、ベンダープレフィックスも書かなきゃいけないし、画像の最適化もしたいし、他にも他にも……


め、めんどくさ〜〜い!


📣 なら自動化しましょう!
簡単に導入できて、カスタマイズ自在、様々な処理を自動化したいそのお悩み、解決できますよ
そう、gulpならね

   Gulp.js

 A toolkit to automate & enhance your workflow      

gulpとは、webページなどの制作における煩雑な処理を自動化するタスクランナーツールです
gulpを使用するにはNode.jsが必要なので、インストールした状態で記事を読み進めてください


gulpにやってもらうこと

まずはサクッとgulpをインストール🥤
プロジェクトのディレクトリを初期化して、

npm init -y

gulpをインストール

npm install --save-dev gulp 


完成品

先に、コピペしたら前項の機能全部使えるpackage.jsonとgulpfileを置いておきます
次項からのタスク別解説をすべて合体するとこの形になります

「説明なんかいらん!とりあえず動くものよこせ!」

といった方は、これをコピペして自由に俺流にカスタマイズしてください………泣いてないわよ

package.json👇
"name""repository" > "url"は適宜変えてください)

package.json
{
  "name": "プロジェクト名",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "repository": {
    "type": "git",
    "url": "git://github.com/xxx/xxx.git"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "browser-sync": "^2.26.7",
    "gulp": "^4.0.2",
    "gulp-autoprefixer": "^7.0.1",
    "gulp-eslint": "^6.0.0",
    "gulp-imagemin": "^7.1.0",
    "gulp-pleeease": "^2.0.2",
    "gulp-plumber": "^1.2.1",
    "gulp-pug": "^4.0.1",
    "gulp-sass": "^4.0.2",
    "gulp-svgmin": "^2.2.0",
    "gulp-uglify": "^3.0.2",
    "node-notifier": "^7.0.2",
    "process": "^0.11.10"
  }
}

上コピペしたら、npm install

gulpfile👇
assets_dirのパスとsrc_fileのパスは適宜変えてください)
(ESLintを使用するので、適宜.eslintrc.jsonを用意してください)

gulpfile.js
const gulp = require('gulp');
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');
const pleeease = require('gulp-pleeease');
const plumber = require('gulp-plumber');
const uglify = require('gulp-uglify');
const eslint = require('gulp-eslint');
const imgMin = require('gulp-imagemin');
const jpgMin = require('imagemin-mozjpeg');
const pngMin = require('imagemin-optipng');
const gifMin = require('imagemin-gifsicle');
const svgMin = require('gulp-svgmin');
const browserSync = require('browser-sync');
const process = require('process');
const notifier = require('node-notifier');
const pug = require('gulp-pug');


// setting
const assets_dir = {
    css: 'assets/css/',
    js: 'assets/js/',
    img: 'assets/img/',
    root: './assets/'
};
const src_file = {
    scss: 'src/scss/**/*.scss',
    js: 'src/js/**/*.js',
    img: 'src/img/**/*.+(jpg|jpeg|png|gif)',
    svg: 'src/img/**/*.svg',
    pug: '**/*.pug'
};


// task
function exit(done){
    process.exit(0);
    done();
}
exports.task = exit;

const errorHandler = function(error) {
    console.log(error.message);
    notifier.notify({
        message: 'Putted the error in the log',
        title: 'ERROR!',
        appIcon: './err_icon.jpeg'
    });
    // gulp.task(exit);
};

function pug_compile(){
    return gulp
        .src(src_file.pug)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(pug())
        .pipe(gulp.dest('./'));
}
exports.task = pug_compile;

function sass_compile(){
    return gulp
        .src(src_file.scss)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(sass())
        .pipe(pleeease())
        .pipe(autoprefixer())
        .pipe(gulp.dest(assets_dir.css));
}
exports.task = sass_compile;

function js_min(){
    return gulp
        .src(src_file.js)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failOnError())
        .pipe(uglify())
        .pipe(gulp.dest(assets_dir.js));
}
exports.task = js_min;

function img_min(){
    return gulp
        .src(src_file.img)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(imgMin([
            jpgMin(),
            pngMin(),
            gifMin({
                optimizationLevel: 3
            })
        ]))
        .pipe(gulp.dest(assets_dir.img));
}
function svg_min(){
    return gulp
        .src(src_file.svg)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(svgMin())
        .pipe(gulp.dest(assets_dir.img));
}
exports.task = img_min;
exports.task = svg_min; 

function serve(done) {
    browserSync.init({
        // ローカルサーバー
        server: {
            baseDir: './'
        },
        port: 3000

        // プロキシ指定
        // proxy: 'http://●●/',
        // Host: '●●.com',
        // open: 'external'
    });
    done();
}
exports.task = serve;

function reload(done){
    browserSync.reload();
    done();
}
exports.task = reload;

function watch(done){
    gulp.watch(src_file.pug, gulp.task(pug_compile));
    gulp.watch(src_file.scss, gulp.task(sass_compile));
    gulp.watch(src_file.js, gulp.task(js_min));
    gulp.watch(src_file.img, gulp.task(img_min));
    gulp.watch(src_file.svg, gulp.task(svg_min));
    gulp.watch(['assets/**/*', '**/*.html'], gulp.task(reload));
    done();
}
exports.task = watch;

// default
gulp.task('default', gulp.series(serve, watch));

上コピペしたら、npx gulpで   $\textrm{So Happy...}$


タスク別解説

前項のこだわりgulpfileの中身を、タスク別で分けて解説していきます
必要なタスクを組み合わせて、自分のプロジェクトに応じたgulpfileを作ってみてください

gulpfileの最後に書いているタスク呼び出しは、この記事👇が参考になります
複数タスクを組み合わせたいときに参考にしてみてください

Gulp - v4 の series と parallel を使って直列・並列処理を制御する  

Gulp v4 で導入された series と parallel を使ってみました。

本記事でのエントリーポイントと出力先パスは以下の通りに設定しています
自分のプロジェクトのディレクトリ構成に応じて、適宜変更してください

gulpfile.js
// setting
const assets_dir = {
    css: 'assets/css/',
    js: 'assets/js/',
    img: 'assets/img/',
    root: './assets/'
};
const src_file = {
    scss: 'src/scss/**/*.scss',
    js: 'src/js/**/*.js',
    img: 'src/img/**/*.+(jpg|jpeg|png|gif)',
    svg: 'src/img/**/*.svg',
    pug: '**/*.pug'
};





✂︎-------------< 以下、解説 >-------------✂︎



ローカルサーバーの立ち上げ(プロキシ指定ver.もあるよ)

npm install --save-dev gulp browser-sync
gulpfile.js
const gulp = require('gulp');
const browserSync = require('browser-sync');

function serve(done) {
    browserSync.init({
        // ローカルサーバー
        server: {
            baseDir: './'
        },
        port: 3000

        // プロキシ指定
        // proxy: 'http://●●/',
        // Host: '●●.com',
        // open: 'external'
    });
    done();
}
exports.task = serve;

gulp.task('serve', serve); //gulp serve 実行でserveタスクが実行される

ローカルサーバーの立ち上げには、browser-syncパッケージを使用します
⚠︎便宜上プロキシ指定しているオプションはコメントアウトしています(基本的にどちらかを設定するため)

  • baseDir
    • サーバー立ち上げた時に参照するディレクトリ
  • port
    • 開放するポート
  • proxy
    • 仮想サーバーのURL
  • Host
    • ホスト名
  • open
    • external 外部URLを開く

このままサーバーを立ち上げると、localhost:3000が開きます
プロキシ指定する際は、serverportオプションを削除して、proxy Host openオプションのコメントアウトを外してください

ファイルの監視、自動リロード

npm install --save-dev gulp browser-sync
gulpfile.js
const gulp = require('gulp');
'browser-sync');

// 自動リロード
function reload(done){
    browserSync.reload();
    done();
}

exports.task = reload;

// ファイルの監視、ファイル更新時自動リロード
function watch(done){
    gulp.watch('監視するファイル(パス含む)', gulp.series('タスク名')); //ファイルの監視
    gulp.watch('監視するファイル(パス含む)', gulp.series(reload)); //ファイル更新時自動リロード
    done();
}

exports.task = watch;

gulp.task('watch', watch); //gulp watch 実行でwatchタスクが実行される

リロードはbrowser-syncパッケージを使用し、監視はgulpパッケージでできます

リロードタスクと監視タスクは分けています
どちらもAPIをそのまま使用するので、特にこちらでオプションを指定する必要はありません

ファイル監視のタスクでは、第一引数のファイルが変更された時に、第二引数のタスクが実行されます
ファイル更新時自動リロードのタスクでは、第一引数のファイルが変更された時に、第二引数のreloadタスクが実行されます

監視したいファイルを複数指定したい時は配列に入れましょう

ビルド失敗時のデスクトップ通知

npm install --save-dev gulp node-notifier process
gulpfile.js
const gulp = require('gulp');
const process = require('process');
const notifier = require('node-notifier');

// gulpの停止
// function exit(done){
//  process.exit(0);
//  done();
// }
// exports.task = exit;

// タスク失敗通知
const errorHandler = function(error) {
    console.log(error.message);
    notifier.notify({
        message: 'Putted the error in the log',
        title: 'ERROR!',
        appIcon: './err_icon.jpeg'
    });
    // gulp.task(exit);
};

⚠︎次項以降でこのタスクを使用するため、便宜上プロセス停止部分はコメントアウトしています
エラー吐いた時にプロセスも終了したい場合は、このコメントアウトを外してください

プロセス制御にprocessパッケージ、デスクトップ通知にnode-notifierパッケージを使用します
動作するとこんな感じ👇
スクリーンショット 2020-09-02 17.26.26.png

  • message
    • 通知の本文
  • title
    • 通知の見出し
  • appIcon
    • 画像でいうと現場猫の部分 なにもヨシ!ではない
      癒し画像にするとエラー吐いても心穏やかにいられるよ

エラーログはコンソールに吐き出され、プロセスは終了します
このタスクは基本的に独立して使用するものではなく、他のタスクに組み込んで使用するので、exports.taskでタスク定義は行いません

画像の最適化

npm install --save-dev gulp gulp-plumber gulp-imagemin gulp-svgmin
gulpfile.js
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const imgMin = require('gulp-imagemin');
const svgMin = require('gulp-svgmin');
const jpgMin = require('imagemin-mozjpeg');
const pngMin = require('imagemin-optipng');
const gifMin = require('imagemin-gifsicle');

function img_min(){
    return gulp
        .src(src_file.img)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(imgMin([
            jpgMin(),
            pngMin(),
            gifMin({
                optimizationLevel: 3
            })
        ]))
        .pipe(gulp.dest(assets_dir.img));
}
function svg_min(){
    return gulp
        .src(src_file.svg)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(svgMin())
        .pipe(gulp.dest(assets_dir.img));
}
exports.task = img_min;
exports.task = svg_min; 

gulp.task('imageMin', gulp.parallel(img_min, svg_min)); //gulp imageMin 実行でimg_minタスクとsvg_minタスクが実行される

エラー起因のプロセス強制終了を防ぐためにgulp-plumberパッケージ、
画像圧縮するためにgulp-imagemin gulp-svgminパッケージを使用し、
画像ファイルそれぞれの拡張子に対応するため、imagemin-mozjpeg imagemin-optipng imagemin-gifsicleプラグインを呼び出しています

  • plumber
  • imgMin
    • gifMin
      • optimizationLevel
        最適化レベルを1〜3で指定します
        今回は一番レベルの高い3を指定しています 時間はかかりますがより精密に最適化が行われます

タスク内では、
エントリーポイントの指定 → plumberの起動 → 最適化 → 指定した出力先に吐き出し
の順で動作しています

pugの使用とコンパイル

npm install --save-dev gulp gulp-pug gulp-plumber
gulpfile.js
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const pug = require('gulp-pug');

function pug_compile(){
    return gulp
        .src(src_file.pug)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(pug())
        .pipe(gulp.dest('./'));
}
exports.task = pug_compile;

gulp.task('pug', pug_compile); //gulp pug 実行でpug_compileタスクが実行される

エラー起因のプロセス強制終了を防ぐためにgulp-plumberパッケージ、
pugの使用、HTMLへのコンパイルをするためにgulp-pugパッケージを使用しています

タスク内では、
エントリーポイントの指定 → plumberの起動 → pugのコンパイル → 指定した出力先に吐き出し
の順で動作しています

sassのコンパイル、ベンダープレフィックスの自動付与、cssの圧縮

npm install --save-dev gulp gulp-sass gulp-plumber gulp-pleeease gulp-autoprefixer
gulpfile.js
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const pleeease = require('gulp-pleeease');
const sass = require('gulp-sass');
const autoprefixer = require('gulp-autoprefixer');

function sass_compile(){
    return gulp
        .src(src_file.scss)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(sass())
        .pipe(pleeease())
        .pipe(autoprefixer())
        .pipe(gulp.dest(assets_dir.css));
}

exports.task = sass_compile;

gulp.task('sass', sass_compile); //gulp sass 実行でsass_compileタスクが実行される

エラー起因のプロセス強制終了を防ぐためにgulp-plumberパッケージ、
sassの使用、cssへのコンパイルをするためにgulp-sassパッケージ、
コンパイルされたcssの圧縮をするためにgulp-pleeeaseパッケージ、
ベンダープレフィックスの自動付与をするためにgulp-autoprefixerパッケージを使用しています

タスク内では、
エントリーポイントの指定 → plumberの起動 → sassのコンパイル → cssの圧縮 → ベンダープレフィックスの付与 → 指定した出力先に吐き出し
の順で動作しています

Javascriptの検証、圧縮

npm install --save-dev gulp gulp-plumber gulp-uglify gulp-eslint
gulpfile.js
const gulp = require('gulp');
const plumber = require('gulp-plumber');
const uglify = require('gulp-uglify');
const eslint = require('gulp-eslint');

function js_min(){
    return gulp
        .src(src_file.js)
        .pipe(plumber({
            errorHandler: errorHandler
        }))
        .pipe(eslint())
        .pipe(eslint.format())
        .pipe(eslint.failOnError())
        .pipe(uglify())
        .pipe(gulp.dest(assets_dir.js));
}
exports.task = js_min;

gulp.task('jsMin', js_min); //gulp jsMin 実行でjs_minタスクが実行される
eslintrc.json
{
  "extends": ["eslint:recommended"],
  "env": {
    "browser": true
  }
}

エラー起因のプロセス強制終了を防ぐためにgulp-plumberパッケージ、
構文チェックのためにgulp-eslintパッケージ、
Javascriptの圧縮をするためにgulp-uglifyパッケージを使用しています

ESLintを使用するには設定ファイルが必要です
.eslintrc.jsonを用意します
中身では、ESLintの推奨設定を継承して、ESLintで構文チェックする対象コードの実行環境を指定しています

タスク内では、
エントリーポイントの指定 → plumberの起動 → 構文チェック → Javascriptの圧縮 → 指定した出力先に吐き出し
の順で動作しています




以上!
面倒で煩雑な処理は全部gulpにお任せすれば、コーディングに集中できますね🎉

コピペしてうまく動作しないなどの不具合があったり、コードに間違いなどありましたら、編集リクエストやコメントで教えていただけますと助かります🙇‍♀️

おまけ

今回は紹介しませんでしたが、Typescriptのパッケージもあるみたい
https://www.npmjs.com/package/gulp-typescript

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?