• 作成日:

gulp4の旧設定について

//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;