
目次
はじめに
Gulpは、Web開発におけるタスクランナーとして広く利用されています。
特に、フロントエンドのビルドプロセスを自動化するためのツールとして非常に便利です。
最近、Gulpのバージョン5がリリースされたので、今回はGulpの最新バージョンへのアップデート方法をすごく簡単に解説します。
私は長らくGulp3を使っていましたが、そろそろGulp4にしなければと思っていた矢先に、今年の3月にGulp5がリリースされました。この機会に、せっかくのいい機会なので職場も自宅もGulp5に対応させていきます。
※Gulp4の環境も作ってはいたのですが、結局慣れているGulp 3を使いつづけていました。すでにGulp4が登場してからは5年ほどたっているようです。。。
ローカルインストールすすめ
初心者はローカルインストールがいいとか、わからない人はとりあえずグローバルにとか、いろいろな意見を目にしますが、慣れてくれば慣れてくるほどローカルインストールの方が融通が利いて便利に感じます。
私は今バージョンが3~5までの環境が一つのパソコンの中にあるので、外注さんや一緒に開発している人のバージョンに合わせて作業できたりと、多少調節が必要になっても柔軟に対応することができている為です。
今回はローカルインストール大前提で簡単に解説していきます。
新しい環境を作る場合
任意の場所にインストールするだけです。以下のコマンドを実行します。
npm uninstall gulp -D
npm uninstall gulp-cli -D
これだけで完了!Gulpのバージョンを確認してみましょう!
npx gulp -v
既存の環境をバージョンアップする場合
まず、既存のGulpをアンインストールしてから新しいバージョンをインストールします。
以下のコマンドでアンインストールできます。
npm uninstall gulp -D
npm uninstall gulp-cli -D
gulpfile.jsの変更点とその他の注意点
基本的にgulpfile.jsの記述は、バージョン4とさほど変わりません。
私はGulp3から4への移行時に苦戦した記憶がありますが、chatGPTにもアシストしてもらってるからか、Gulp5はスムーズに移行できた印象です。
一点大きく変更したところとしてはgulpfile.jsからgulpfile.mjsに変更しました。
EMモジュールとmjsについて
Gulp 5以降では、JavaScriptのモジュールシステムであるECMAScriptモジュール(ESモジュール)がサポートされています。これにより、.mjs
ファイルを使ってモジュールを定義・インポートすることが可能になりました。
ESモジュールとは?
ESモジュールは、JavaScriptの標準モジュールシステムです。従来のCommonJSモジュールシステム(require
やmodule.exports
を使用するもの)とは異なり、ESモジュールはimport
とexport
のキーワードを使用します。これにより、モジュールの依存関係がより明示的かつ簡潔に記述できるようになります。
.mjsファイルの利用方法
GulpのタスクをESモジュールとして記述する場合、.mjs
拡張子を使用することが推奨されます。以下に、簡単な例を示します。
// gulpfile.mjs
import gulp from 'gulp';
import sass from 'gulp-sass';
gulp.task('sass', function() {
return gulp.src('src/scss/*.scss')
.pipe(sass())
.pipe(gulp.dest('dist/css'));
});
export default gulp.task('default', gulp.series('sass'));
この例では、import
を使用してgulp
とsass
モジュールをインポートし、Gulpのタスクを定義しています。
その他の注意点
Node.jsの10.13のサポートが終了しています。
バージョン10.13以前のものを使用している方は、各バージョンの維持が少し大変になるかもしれません。
そのため、Node.jsのバージョンアップも併せて検討すると良いでしょう。
私が使っている感じでは、Gulp5はGulp4の頃とあまり変わらずに使用できていますが、最新の環境での動作確認は必須です。
※5をいれてから3の確認はまだ全然行っていないので、ひょっとしたら調節等が今後必要になるかもしれません。
Gulp5で動作するgulpfile.mjsの例
まだ完全に理解しているわけではありませんが、Gulp 5で動作するgulpfile.jsの一例を以下に示します。
このファイルは、圧縮作業を効率的に行うために極力コメントを記載しています。
不要な機能は削除しながら参考にしてください。
import gulp from 'gulp'; // gulpをインポート
const { series, src, dest, watch } = gulp; // series, src, dest, watchがそのまま使えるように
// プラグインのインポート
import plumber from 'gulp-plumber'; // エラーが発生してもタスクを停止しない
import notify from 'gulp-notify'; // エラー発生時にデスクトップ通知を行う
import browserSync from 'browser-sync'; // ローカルサーバーを起動し、ブラウザの自動リロードを行う
import gulpSass from 'gulp-sass'; // Sassファイルをコンパイルする
import sass from 'sass'; // Dart Sass
import sassGlob from 'gulp-sass-glob'; // Sassのimport文を簡潔に書くためのプラグイン
import csscomb from 'gulp-csscomb'; // CSSプロパティをソートする
import connect from 'gulp-connect-php'; // PHPサーバーを立ち上げる
import sourcemaps from 'gulp-sourcemaps'; // ソースマップを作成する
import postcss from 'gulp-postcss'; // PostCSSを利用する
import cssnano from 'cssnano'; // CSSファイルを圧縮する
import uglify from 'gulp-uglify'; // JavaScriptファイルを圧縮する
import strip from 'gulp-strip-comments'; // コメントを削除する
import mqpacker from 'css-mqpacker'; // メディアクエリをまとめる
import discardComments from 'postcss-discard-comments'; // CSSのコメントを削除する
import autoprefixer from 'autoprefixer'; // ベンダープレフィックスを付与する
import purgecss from 'gulp-purgecss'; // 未使用のCSSセレクタを削除する
import imagemin from 'gulp-imagemin'; // 画像ファイルを圧縮する
import mozjpeg from 'imagemin-mozjpeg'; // JPEG画像を圧縮する
import pngquant from 'imagemin-pngquant'; // PNG画像を圧縮する
import webp from 'gulp-webp'; // 画像ファイルをWEBPに変換する
import rename from 'gulp-rename'; // ファイル名を変更する
import log from 'fancy-log'; // ログを抑制するためのモジュール
import path from 'path'; // パス操作用
import through from 'through2'; // ストリーム操作用
const browser = browserSync.create();
const sassProcessor = gulpSass(sass);
// ログ出力を抑制するための関数
const suppressLogging = (done) => {
log.level = 'error';
done();
};
// 参照元パス
const srcPath = {
img: 'src/image/**/*.{png,jpg,gif,svg}', // 画像ファイルのソース
scss: 'src/scss/**/*.scss', // Sassファイルのソース
js: 'src/js/**/*.js', // JSファイルのソース
php: 'dist/**/*.php', // PHPファイルのソース
html: 'dist/**/*.html' // HTMLファイルのソース
};
// 出力先パス
const destPath = {
img: 'dist/image', // 画像ファイルの出力先
css: 'dist/css', // CSSファイルの出力先
js: 'dist/js' // JSファイルの出力先
};
// PHPサーバーを立ち上げ、BrowserSyncでプレビュー表示するタスク
function connectSync(done) {
connect.server({
port: 8080, // サーバーのポート番号
base: 'dist/' // サーバーのベースディレクトリ
}, function() {
browser.init({
proxy: 'localhost:8080', // Proxy設定をlocalhostに変更
baseDir: 'dist/' // ベースディレクトリを設定
});
});
done();
}
// ブラウザをリロードするタスク
function reload(done) {
browser.reload(); // BrowserSyncを使ってブラウザをリロードする
done();
}
// サーバーを停止するタスク
function serverClose(done) {
process.exit(); // サーバーを停止する
done();
}
// Sassをコンパイルし、CSSを生成するタスク
const sassTask = () => (
src(srcPath.scss) // Sassファイルのソース
.pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") })) // エラー時に通知
.pipe(sourcemaps.init()) // ソースマップを初期化
.pipe(sassGlob()) // Sassのimport文をまとめる
.pipe(sassProcessor().on('error', sassProcessor.logError)) // Sassをコンパイル
.pipe(csscomb()) // CSSプロパティを整形
.pipe(postcss([
autoprefixer('last 2 versions'), // ベンダープレフィックスを付与
mqpacker(), // メディアクエリをまとめる
discardComments({ removeAll: true }) // CSSコメントを削除
]))
.pipe(purgecss({ // 未使用のCSSセレクタを削除
content: [srcPath.html, srcPath.php, srcPath.js]
}))
.pipe(sourcemaps.write('.')) // ソースマップを書き出す
.pipe(dest(destPath.css)) // 出力先
.pipe(browser.stream()) // ブラウザをリロード
);
// JSを圧縮し、コメントアウトを削除するタスク
const scriptsTask = () => (
src(srcPath.js) // JSファイルのソース
.pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") })) // エラー時に通知
.pipe(strip()) // コメントアウトを削除
.pipe(uglify()) // JSを圧縮
.pipe(dest(destPath.js)) // 出力先
);
let totalSizeBefore = 0;
let totalSizeAfter = 0;
// 画像を圧縮するタスク
const compressImages = () => (
src(srcPath.img, { encoding: false }) // 画像ファイルのソース
.pipe(plumber({
errorHandler: (err) => {
notify.onError({
title: `Gulp error in ${err.plugin}`,
message: err.toString()
})(err);
}
})) // エラー時に通知
.pipe(through.obj(function(file, enc, cb) {
totalSizeBefore += file.stat.size; // 圧縮前のファイルサイズを累積
const sizeMB = file.stat.size / (1024 * 1024); // ファイルサイズをMB単位で取得
let imageminPlugins;
if (sizeMB > 2) { // 2MB以上のファイル
imageminPlugins = [
mozjpeg({ quality: 50, progressive: true }), // JPEGの圧縮
pngquant({ quality: [0.4, 0.5] }), // PNGの圧縮
];
} else if (sizeMB > 1) { // 1MB以上2MB未満のファイル
imageminPlugins = [
mozjpeg({ quality: 65, progressive: true }), // JPEGの圧縮
pngquant({ quality: [0.5, 0.6] }) // PNGの圧縮
];
} else { // 1MB未満のファイル
imageminPlugins = [
mozjpeg({ quality: 75, progressive: true }), // JPEGの圧縮
pngquant({ quality: [0.6, 0.8] }) // PNGの圧縮
];
}
gulp.src(file.path, { encoding: false })
.pipe(imagemin(imageminPlugins, { verbose: false })) // verbose: false で詳細なログを抑制
.pipe(rename((filePath) => {
filePath.dirname = path.relative(file.base, path.dirname(file.path)); // 元のディレクトリ構造を保持
}))
.pipe(dest(destPath.img))
.on('data', (data) => {
totalSizeAfter += data.stat.size; // 圧縮後のファイルサイズを累積
})
.on('end', () => cb());
}))
);
// 画像をWEBPに変換するタスク
const convertToWebP = () => (
src(srcPath.img, { encoding: false }) // 画像ファイルのソース
.pipe(plumber({
errorHandler: (err) => {
notify.onError({
title: `Gulp error in ${err.plugin}`,
message: err.toString()
})(err);
}
})) // エラー時に通知
.pipe(rename((filePath, file) => {
filePath.basename += filePath.extname; // ファイル名に元の拡張子を追加
filePath.dirname = path.relative(file.base, path.dirname(file.path)); // 元のディレクトリ構造を保持
}))
.pipe(webp({ quality: 85 })) // WEBPに変換
.pipe(dest(destPath.img))
);
// 画像処理タスクを一つにまとめる
const imgTask = series(compressImages, convertToWebP, (done) => {
const totalReduction = ((totalSizeBefore - totalSizeAfter) / totalSizeBefore) * 100;
log.info(`Total size before compression: ${(totalSizeBefore / (1024 * 1024)).toFixed(2)} MB`);
log.info(`Total size after compression: ${(totalSizeAfter / (1024 * 1024)).toFixed(2)} MB`);
log.info(`Total size reduction: ${((totalSizeBefore - totalSizeAfter) / (1024 * 1024)).toFixed(2)} MB`);
log.info(`Total size reduction percentage: ${totalReduction.toFixed(2)}%`);
done();
});
// ファイルの変更を監視するタスク
const watchFiles = (done) => {
watch(srcPath.scss, sassTask); // Sassファイルが変更されたらコンパイルする
watch(srcPath.js, scriptsTask); // JSファイルが変更されたら処理する
watch(srcPath.php, reload); // PHPファイルが変更されたらリロードする
watch(srcPath.img, imgTask); // 画像ファイルが変更されたら圧縮とWEBP変換を行う
done();
};
// デフォルトタスク(Gulpを実行した際に動くタスク)
export default series(suppressLogging, connectSync, watchFiles);
// 個別タスクをエクスポート
export { sassTask, scriptsTask, imgTask };
必要なプラグイン一覧
上記Gulp5で動作するgulpfile.mjsの例を使用するために必要なプラグインは以下の通りです。
- gulp: Gulpのメインパッケージ
- gulp-plumber: エラーが発生してもタスクを停止しない
- gulp-notify: エラー発生時にデスクトップ通知を行う
- browser-sync: ローカルサーバーを起動し、ブラウザの自動リロードを行う
- gulp-sass: Sassファイルをコンパイルする
- sass: Dart Sass
- gulp-sass-glob: Sassのimport文を簡潔に書くためのプラグイン
- gulp-csscomb: CSSプロパティをソートする
- gulp-connect-php: PHPサーバーを立ち上げる
- gulp-sourcemaps: ソースマップを作成する
- gulp-postcss: PostCSSを利用する
- cssnano: CSSファイルを圧縮する
- gulp-uglify: JavaScriptファイルを圧縮する
- gulp-strip-comments: コメントを削除する
- css-mqpacker: メディアクエリをまとめる
- postcss-discard-comments: CSSのコメントを削除する
- autoprefixer: ベンダープレフィックスを付与する
- gulp-purgecss: 未使用のCSSセレクタを削除する
- gulp-imagemin: 画像ファイルを圧縮する
- imagemin-mozjpeg: JPEG画像を圧縮する
- imagemin-pngquant: PNG画像を圧縮する
- gulp-webp: 画像ファイルをWEBPに変換する
- gulp-rename: ファイル名を変更する
- fancy-log: ログを抑制するためのモジュール
- path: パス操作用
- fs: ファイルシステム操作用
- through2: ストリーム操作用
これらのプラグインを一括でインストールするには、以下のコマンドを使用します。
npm install gulp gulp-plumber gulp-notify browser-sync gulp-sass sass gulp-sass-glob gulp-csscomb gulp-connect-php gulp-sourcemaps gulp-postcss cssnano gulp-uglify gulp-strip-comments css-mqpacker postcss-discard-comments autoprefixer gulp-purgecss gulp-imagemin imagemin-mozjpeg imagemin-pngquant gulp-webp gulp-rename fancy-log path fs through2
まとめ
職場によっては、様々な理由で自由にバージョンを変えられない方もいると思いますが、新しい技術やツールの知識を取り入れることは重要です。特に、Gulpのようなツールはバージョンアップによって機能が大幅に向上することがあるため、最新情報を常にキャッチアップすることが求められます。ぜひ、Gulp 5へのアップデートを試してみてください。
以上が、Gulp 5へのアップデート方法とその利点についての解説でした。これからも最新の技術情報を共有していきますので、引き続きご期待ください。