gulpfile.jsの中身をタスク毎に分割しました
gulpfile.jsの中身をずっとタスク毎に分割できたら、管理しやすいし、かっこいいなぁと思っていて、何度も挑戦しては「あ、無理だ…」っていうのを繰り返していたら、今回タスク毎に分けることに成功したので記事にしてみました。
今回はタスクを分割することにフォーカスしているので、gulpのプラグイン が非推奨のものだったり、あまりよろしくない書き方をしている可能性もありますので、あくまで参考程度にみていただけたらと思います。(まだまだ試行錯誤中ですので…)
タスク分割前の状態
フォルダ構造
srcフォルダ:開発用ディレクトリ
wwwフォルダ:公開用ディレクトリ (人によってはdistフォルダの場合もあります、この辺はお好きな名前で🙆♂️)
configフォルダ
gulp.config.js(gulpで使用するパスをまとめたファイルになります、こちらも名前はお好きな名前で🙆♂️)
module.exports = {
dest: ['./www/'],
html:{
src: ['./src/*.html', './src/**/*.html'],
watch: ['./src/*.html', './src/**/*.html'],
dest: ['./www/']
},
scss: {
src: ['./src/assets/scss/*.scss'],
watch: ['./src/assets/scss/*.scss'],
dest: ['./www/assets/css']
},
js: {
src: ['./src/assets/js/*.js','!src/assets/js/_*.js'],
watch: ['./src/assets/js/*.js','./src/assets/js/modules/_*.js'],
dest: ['./www/assets/js']
},
img: {
src: ['./src/assets/img/*.png', './src/assets/img/*.jpg', './src/assets/img/*.svg' ,'./src/assets/img/*.ico' ,'./src/assets/img/*.gif'],
watch: ['./src/assets/img/*.png', './src/assets/img/*.jpg', './src/assets/img/*.svg' ,'./src/assets/img/*.ico' ,'./src/assets/img/*.gif'],
dest: ['./www/assets/img']
}
}
webpack.config.js(webpackの設定ファイル)
こちらの設定方法はここでは割愛させていただきます。
詳しくは下記↓↓
「ポートフォリオに導入しているwebpack」
gulpfile.js
const { src, dest, series, watch } = require('gulp');
const gulpSass = require('gulp-sass');
const fibers = require('fibers');
const postCss = require('gulp-postcss');
gulpSass.compiler = require('sass');
const cssNano = require('cssnano');
const cssMediaQuery = require('gulp-group-css-media-queries');
const clean = require('gulp-clean');
const browserSync = require('browser-sync');
const autoPrefixer = require('autoprefixer');
const imageMin = require('gulp-imagemin');
const pngQuant = require('imagemin-pngquant');
const mozJpeg = require('imagemin-mozjpeg');
const svgo = require('imagemin-svgo');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const ftp = require('vinyl-ftp');
const fancyLog = require('fancy-log');
const babel = require('gulp-babel');
const open = require('gulp-open');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
// gulp パス 設定ファイル
const configPath = require("./config/gulp.config");
// webpack 設定ファイル読み込み
const webpackConfig = require("./config/webpack.config");
// browserSync ローカルサーバ起動
function localServerStart(done){
browserSync.init({
port: 3000,
notify: false,
server: {
baseDir: '../gulp-sample'
},
startPath: './www/index.html',
open: 'external',
})
done()
}
// browserSync リロード
function browserReload(done) {
browserSync.reload()
done()
}
// htmlコピー
function htmlCopy(done){
src(configPath.html.src)
.pipe(plumber())
.pipe(dest(configPath.html.dest))
done()
}
// SCSS → CSSコンパイル & ベンダープレフィックス付与 & CSS圧縮
function scssCompile(done) {
src(configPath.scss.src, { sourcemaps: true })
.pipe(plumber({
errorHandler: notify.onError('<%= error.message %>')
}))
.pipe(gulpSass({
fiber: fibers,
style: 'expanded'
}))
.pipe(cssMediaQuery()),
.pipe(postCss([
autoPrefixer({
grid: "autoplace",
}),
cssNano()
]))
.pipe(rename({extname: '.min.css'}))
.pipe(dest(configPath.scss.dest), { sourcemaps: true })
done()
}
// js babel&圧縮
function jsCompile(done){
src(configPath.js.src)
.pipe(plumber({
errorHandler: notify.onError('<%= error.message %>')
}))
.pipe(uglify())
.pipe(dest(configPath.js.dest))
done()
}
// webpack & babel
function webpackBandle(done) {
// ☆ webpackStreamの第2引数にwebpackを渡す☆
webpackStream(webpackConfig, webpack)
.pipe(dest(configPath.js.dest));
done()
}
// 画像圧縮
function imgMinify(done){
src(configPath.img.src)
.pipe(plumber())
.pipe(imageMin([
pngQuant(),
mozJpeg(),
svgo()
]))
.pipe(dest(configPath.img.dest))
done()
}
// wwwフォルダ 削除
function cleanDirectory(done){
src(configPath.dest,{read: false})
.pipe(clean())
done()
}
// FTPアップロード
function ftpUpload(done){
const ftpOptions = {
host: 'サーバーURL',
user: 'ユーザー名',
password: 'パスワード',
log: fancyLog
}
const connect = ftp.create(ftpOptions)
const ftpUploadFiles = './www/**'
const remoteDistDir = './gulp-sample/'
src(ftpUploadFiles)
.pipe(connect.dest(remoteDistDir))
done()
}
// アップロード先 サイト開く
function publicOpen(done){
src('./').pipe(open({uri: 'サイトを開くURL'}))
done()
}
// ファイル監視
function watchLoad() {
watch(configPath.html.watch, series(htmlCopy, browserReload));
watch(configPath.scss.watch, series(scssCompile, browserReload));
watch(configPath.js.watch, series(jsCompile, webpackBandle, browserReload));
watch(configPath.img.watch, series(imgMinify, browserReload));
}
// webpack エラーチェック用
/* process.on('unhandledRejection', (reason, p) => {
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
}) */
// 各タスク実行 コマンド → gulp
exports.default = series(htmlcopy, scssCompile, jsCompile, fontCopy, webpackBandle, imgMinify, localServerStart, watchLoad);
// WWWフォルダ削除 コマンド → gulp clean
exports.clean = series(cleanDirectory)
// WWWフォルダコンパイル コマンド → gulp compile
exports.compile = series(htmlcopy, scssCompile, jsCompile, fontCopy, webpackBandle, imgMinify)
// FTPタスク実行 コマンド → gulp ftp
exports.ftp = series(ftpUpload, publicOpen)
記載しているタスクとしては8つです
・browserSync ローカルサーバ起動
・srcフォルダ内のhtml→wwwフォルダ内へコピー
・srcフォルダ内のscssをwwwフォルダ内のcssへコンパイル(ベンダープレフィックス付与やcss圧縮)
・srcフォルダ内のjsをwwwフォルダ内のjsへコンパイル(webpackを用いてのbabelやjs圧縮)
・画像圧縮
・wwwフォルダの削除
・サーバーへのアップロード
・ファイルの監視
タスク分割後の状態
タスク分割前の状態はgulpfile.jsのファイルをgulp-sampleフォルダ直下に置いていました。タスク分割後はgulpfile.jsをファイルとしてではなく、フォルダにした状態でgulp-sampleフォルダ直下に置きます。
そして、gulpfile.jsフォルダ内にtasksフォルダを作成し、その中に8つのタスクをjsファイルとして置きます。1つずつ見ていきましょう!
・browserSync ローカルサーバ起動 → browserSync.js
const { series } = require('gulp');
const browserSync = require('browser-sync');
// browserSync ローカルサーバ起動
function localServerStart(done){
browserSync.init({
port: 3000,
notify: false,
server: {
baseDir: '../gulp-sample'
},
startPath: './www/index.html',
open: 'external',
})
done()
}
// browserSync リロード
function browserReload(done) {
browserSync.reload()
done()
}
exports.browserSync = series(localServerStart, browserReload);
・srcフォルダ内のhtml→wwwフォルダ内へコピー → htmlCopy.js
const { src, dest, series } = require('gulp');
const plumber = require('gulp-plumber');
// gulp パス 設定ファイル
const configPath = require("../config/gulp.config");
// htmlコピー
function htmlCopy(done){
src(configPath.html.src)
.pipe(plumber())
.pipe(dest(configPath.html.dest))
done()
}
exports.htmlCopy = series(htmlCopy);
・srcフォルダ内のscssをwwwフォルダ内のcssへコンパイル(ベンダープレフィックス付与やcss圧縮) → scssCompile.js
const { src, dest, series } = require('gulp');
const gulpSass = require('gulp-sass');
const fibers = require('fibers');
const postCss = require('gulp-postcss');
gulpSass.compiler = require('sass');
const autoPrefixer = require('autoprefixer');
const cssNano = require('cssnano');
const groupMediaQuery = require('gulp-group-css-media-queries');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const rename = require('gulp-rename');
// gulp パス 設定ファイル
const configPath = require("../config/gulp.config");
function scssCompile(done) {
src(configPath.scss.src, { sourcemaps: true })
.pipe(plumber({
errorHandler: notify.onError('<%= error.message %>')
}))
.pipe(gulpSass({
fiber: fibers,
style: 'expanded'
}))
.pipe(groupMediaQuery())
.pipe(postCss([
autoPrefixer({
grid: 'autoplace',
}),
cssNano()
]))
.pipe(rename({extname: '.min.css'}))
.pipe(dest(configPath.scss.dest), { sourcemaps: true })
done()
}
exports.scssCompile = series(scssCompile);
・srcフォルダ内のjsをwwwフォルダ内のjsへコンパイル(webpackを用いてのbabelやjs圧縮)→ jsCompile.js
const { src, dest, series } = require('gulp');
const uglify = require('gulp-uglify');
const plumber = require('gulp-plumber');
const notify = require('gulp-notify');
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
// gulp パス 設定ファイル
const configPath = require("../config/gulp.config");
// webpack 設定ファイル読み込み
const webpackConfig = require("../config/webpack.config");
// js babel&圧縮
function jsCompile(done){
src(configPath.js.src)
.pipe(plumber({
errorHandler: notify.onError('<%= error.message %>')
}))
.pipe(uglify())
.pipe(dest(configPath.js.dest))
done()
}
// webpack & babel
function webpackBandle(done) {
// ☆ webpackStreamの第2引数にwebpackを渡す☆
webpackStream(webpackConfig, webpack)
.pipe(dest(configPath.js.dest));
done()
}
exports.jsCompile = series(jsCompile, webpackBandle);
・画像圧縮 → imgMinify.js
const { src, dest, series } = require('gulp');
const imageMin = require('gulp-imagemin');
const pngQuant = require('imagemin-pngquant');
const mozJpeg = require('imagemin-mozjpeg');
const svgo = require('imagemin-svgo');
const plumber = require('gulp-plumber');
// gulp パス 設定ファイル
const configPath = require("../config/gulp.config");
// 画像圧縮
function imgMinify(done){
src(configPath.img.src)
.pipe(plumber())
.pipe(imageMin([
pngQuant(),
mozJpeg(),
svgo()
]))
.pipe(dest(configPath.img.dest))
done()
}
exports.imgMinify = series(imgMinify);
・wwwフォルダの削除 → clean.js
const { src, series } = require('gulp');
const clean = require('gulp-clean');
// gulp パス 設定ファイル
const configPath = require("../config/gulp.config");
// wwwフォルダ 削除
function cleanDirectory(done){
src(configPath.dest,{read: false})
.pipe(clean())
done()
}
exports.cleanDirectory = series(cleanDirectory);
・サーバーへのアップロード → ftpUpLoad.js
const { src, series } = require('gulp');
const ftp = require('vinyl-ftp');
const fancyLog = require('fancy-log');
const open = require('gulp-open');
// FTPアップロード
function ftpUpload(done){
const ftpOptions = {
host: 'サーバーURL',
user: 'ユーザー名',
password: 'パスワード',
log: fancyLog
}
const connect = ftp.create(ftpOptions)
const ftpUploadFiles = './www/**'
const remoteDistDir = './gulp-sample/'
src(ftpUploadFiles)
.pipe(connect.dest(remoteDistDir))
done()
}
// アップロード先 サイト開く
function publicOpen(done){
src('./').pipe(open({uri: 'サイトを開くURL'}))
done()
}
exports.ftpUpload = series(ftpUpload,publicOpen);
・ファイルの監視 → watchLoad.js
const { series,watch } = require('gulp');
const browserSync = require('browser-sync');
const { scssCompile } = require("./scssCompile");
const { jsCompile } = require("./jsCompile");
const { imgMinify } = require("./imgMinify");
const { htmlCopy } = require("./htmlCopy");
// gulp パス 設定ファイル
const configPath = require("../config/gulp.config");
// browserSync リロード
function browserReload(done) {
browserSync.reload()
done()
}
// ファイル監視
function watchLoad() {
watch(configPath.html.watch, series(htmlCopy, browserReload));
watch(configPath.scss.watch, series(scssCompile, browserReload));
watch(configPath.js.watch, series(jsCompile, browserReload));
watch(configPath.img.watch, series(imgMinify, browserReload));
}
exports.watchLoad = series(watchLoad);
タスクを分割できたら、各タスクをgulpfile.jsフォルダ直下にあるindex.jsファイルにまとめます。
index.js
const { series } = require('gulp');
const { browserSync } = require("./tasks/browserSync");
const { scssCompile } = require("./tasks/scssCompile");
const { jsCompile } = require("./tasks/jsCompile");
const { imgMinify } = require("./tasks/imgMinify");
const { htmlCopy } = require("./tasks/htmlCopy");
const { ftpUpload } = require("./tasks/ftpUpLoad");
const { cleanDirectory } = require("./tasks/clean");
const { watchLoad } = require("./tasks/watchLoad");
// browserSync 実行コマンド → gulp browserSync
exports.browserSync = browserSync;
// htmlコピー 実行コマンド → gulp htmlCopy
exports.htmlCopy = htmlCopy;
// scssコンパイル&圧縮 実行コマンド → gulp scssCompile
exports.scssCompile = scssCompile;
// JavaScriptコンパイル&圧縮 実行コマンド → gulp jsCompile
exports.jsCompile = jsCompile;
// 画像最適化 実行コマンド → gulp imgMinify
exports.imgMinify = imgMinify;
// FTPアップロード 実行コマンド → gulp ftp
exports.ftp = ftpUpload;
// wwwフォルダ内削除 実行コマンド → gulp clean
exports.clean = cleanDirectory;
// browserSync + 各タスク全て 実行コマンド → gulp
exports.default = series(browserSync, htmlCopy, scssCompile, jsCompile, imgMinify, watchLoad);
// 各タスク全て 実行コマンド → gulp compile
exports.compile = series(htmlCopy, scssCompile, jsCompile, imgMinify);
これでgulpfile.jsフォルダ内を見れば、パッと見でどこに何のタスクが書かれているのかが探しやすく、管理がしやすくなったのではないかと思います。(最終的にはチーム毎で定めたルールだったり、各々の好みもあるのでタスク毎に分けなくてもいいよっていう意見もあるかと思いますので、なにかしら参考になれば嬉しいです。)
ただ、自分としてはタスク毎に分けられたもののgulpfile.jsファイルをgulpfile.jsフォルダとした時にフォルダ名に拡張子として.jsが付くのが若干、違和感があるのでフォルダ名をgulpfile.jsとしないで済む方法がないのか知りたいです。
参考記事
gulp4再入門 gulpfileの分割とnodeモジュールの利用
https://qiita.com/masato_makino/items/ad11058e1a8a009abbdf
gulp公式ドキュメント
https://gulpjs.com/docs/en/getting-started/javascript-and-gulpfiles/#splitting-a-gulpfile