//gulpとgulpのパッケージを読み込み
const { src, dest, watch, lastRun, parallel, series } = require("gulp");
const sass = require("gulp-sass"); //Sassを使う
const glob = require("gulp-sass-glob"); //sassのimportを楽にする
const postcss = require("gulp-postcss"); //Autoprefixと一緒に使うもの
const autoprefixer = require("autoprefixer"); //Autoprefix
const plumber = require("gulp-plumber"); //エラーでも強制終了させない
const notify = require("gulp-notify"); //エラーのときはデスクトップに通知
const htmlmin = require("gulp-htmlmin"); //htmlの圧縮・整理
const del = require("del"); //ファイル、ディレクトリの削除
const ejs = require("gulp-ejs"); //htmlのパーツ化
const concat = require("gulp-concat"); //ファイルの結合
const order = require("gulp-order"); //指定した順番で並べる
const rename = require("gulp-rename"); //ejsの拡張子を変更
const cleanCSS = require("gulp-clean-css"); //cssの圧縮
const pngquant = require("imagemin-pngquant"); //画像圧縮
const imagemin = require("gulp-imagemin"); //上と同じ
const mozjpeg = require("imagemin-mozjpeg"); //上と同じ
const uglify = require("gulp-uglify"); //script圧縮用
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: ["./src/ejs/**/*.ejs", "!" + "./src/ejs/**/_*.ejs"],
dist: "./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(glob())
.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(glob())
.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(), //最新だとjpegtranだとエラーになる
imagemin.mozjpeg(),
imagemin.optipng(),
imagemin.svgo({
plugins: [
{ removeViewBox: false },
{ removeMetadata: false },
{ removeUnknownsAndDefaults: false },
{ convertShapeToPath: false },
{ collapseGroups: false },
{ cleanupIDs: 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;