#はじめに
gulp4で開発環境を作ったので、全体の流れの覚書きです。
gulpfileのコードは載っけていますが、gulp.jsの詳しい説明は載せてません。
gulpfile設定の時のつまづきメモはこちら。
[gulp4] gulpfileのつまずきアレコレ
###作った環境
- ejsをhtmlに変換、圧縮
- sassをcssに変換、ベンダープレフィックス付与、圧縮、ソースマップ作成
- JSを圧縮、ソースマップ作成、
- 画像を圧縮
- 更新が内容保存されたら、ブラウザを自動でリロードする
ちなみに、作成時の環境はこちらでした。
node v12.16.1
npm v6.13.4
###導入の手順
- node.jsをインストール
- パッケージをインストール
- gulpfile.jsを設定する
#手順1:node.jsをインストール
「作った環境」は、node.jsのパッケージをインストールすることで作れます。
その為にまずはnode.jsをインストールします。
##選択肢①: homebrew,nodebrewでインストール
こちらの記事が参考になりそうです!
MacにNode.jsをインストール
ただ、私はnode.jsはインストール済みでしたが、"nodenv"というものを知り使ってみたかったので「選択肢②」を今回試しました。
##選択肢②:nodenvでインストール
この機会に、プロジェクト毎にnode.jsのバージョンを簡単に切り替えられる**"nodenv"**を入れてみました。
こちらのサイトがわかりやすかったです!
anyenvとnodenvでNode.jsのバージョン管理をしよう!
ただ、私の場合、nodenvを使ってプロジェクト用のnode.jsをインストールする際にnodenv: default-packages file not found
というエラーが出てしまいました。
yarnのインストールと、yarnでdefault-packagesファイルを作る必要があったようです。
echo yarn >> $NODENV_ROOT/default-packages
を打ったらインストールできる様になりました。
このエラー時に参考にさせていただいたサイトはこちら。
nodenv install時にdefault-packages file not foundが出た時のメモ
#手順2:パッケージをインストール
いよいよパッケージをインストールしていく訳なのですが、その前に、どんなものをインストールしたのかを記録するファイル package.json が必要になります。
##手順2-1:package.jsonを生成する
作業ディレクトリに移動して、ターミナルに以下を入力すると、package.jsonが生成されます。
npm init -y
-y
オプションをつけると、ファイル名やファイル説明などの設定項目を全て "yes" で処理したこととなり、デフォルト設定になります。
最初にファイル設定をしたい場合は npm init
と入れて、各項目を埋めていけばOKです。
設定は、package.jsonのファイル内容を書き換えることでいつでも編集できます。
##手順2-2:パッケージをインストールする
パッケージインストールのコマンドは以下の通りです。
ターミナル上で色々文字が動き出してちょっと怖いですが、アンインストールも簡単にできるので恐れず入力します。
//インストール
npm install --save-dev パッケージ名
//一括インストールしたい時
npm install --save-dev パッケージ名1 パッケージ名2 パッケージ名2
//アンインストール
npm uninstall --save-dev パッケージ名
今回使うパッケージは、全て開発環境でのみ使用するので、--save-dev
オプションをつけます。
他にも、npm install パッケージ名 --save-dev
、npm i -D パッケージ名
といった書き方でもOKです。
###メモ: "--save-dev" オプションについて
--save-dev
や -D
オプションを付けると、package.json内の "devDependencies" 項目に、つけずに npm install パッケージ名
とすると "dependencies" 項目に登録されます。
"dependencies"とは、「依存関係」という意味です。
さっくりいうと、こういう感じ。
- devDependencies:開発にのみ使用するパッケージ(gulpなど)
- dependencies:本番環境でも使用するパッケージ (プラグインなど)
##今回インストールするパッケージ一覧
先ほど紹介したコマンドを使用して個別にインストールするか、こちら↓をコピペ。
npm install --save-dev gulp gulp-sass gulp-postcss autoprefixer gulp-clean-css gulp-ejs gulp-htmlmin gulp-uglify del gulp-imagemin imagemin-mozjpeg imagemin-svgo imagemin-pngquant imagemin-gifsicle gulp-watch browser-sync
パッケージの役割は次の通りです。(クリックで各提供元ページに遷移します)
他にもgulpの公式サイトやググると、いろんな便利パッケージを探すことができます。
gulp :タスクランナー
gulp-rename :ファイル名変更
gulp-sass :sassをcssに変換
node-sass-package-importer :.css拡張子のファイル(sanitize.cssなど)をscssファイルで読み込み可にする
gulp-postcss :autoprefixerを使う為に必要
autoprefixer :ベンダープレフィックスを自動付与する
gulp-clean-css :cssを圧縮
gulp-ejs :ejsをhtmlに変換
gulp-htmlmin :htmlを圧縮
gulp-babel :ES6をES5に変換する(IE11が非対応のES6に対応するため)
gulp-uglify :jsを圧縮
del :ファイルを削除する
gulp-imagemin :画像圧縮
imagemin-mozjpeg :jpg用エンコーダー
imagemin-svgo :svg用エンコーダー
imagemin-pngquant :png用エンコーダー
imagemin-gifsicle :gif用エンコーダー
gulp-watch :タスクを監視する
gulp-plumber :エラー検知
gulp-notify :検知したエラーをデスクトップに通知
browser-sync :ファイル保存時にブラウザを自動でリロード
インストールされたら、package.jsonの"devDependencies"項目に、パッケージ名とバージョンがずらっと並んでるはず。
#手順3:gulpfile.jsを設定する
インストールしたパッケージは、gulpfile.jsを設定することで使えるようになります。
##手順3-1: gulpfileを記載する
gulpの公式サイトや、パッケージ提供元の説明を見ながら記載していきます。
出来上がったのはこんな感じ。
const gulp = require('gulp'); //gulp
const rename = require('gulp-rename'); //名前変更
const sass = require('gulp-sass'); //sassコンパイル
const packageImporter = require('node-sass-package-importer'); //cssパッケージのimport用
const postcss = require('gulp-postcss'); //autoprefixerを使うのに必要
const autoprefixer = require('autoprefixer'); //prefixをつける
const cleanCss = require('gulp-clean-css'); //css圧縮
const ejs = require('gulp-ejs'); //ejsコンパイル
const htmlmin = require('gulp-htmlmin'); //html圧縮と整理
const babel = require('gulp-babel'); //jsトランスパイル
const uglify = require('gulp-uglify'); //js圧縮
const del = require('del'); //フォルダやファイルを削除
const imagemin = require('gulp-imagemin'); //画像圧縮
const mozjpeg = require('imagemin-mozjpeg') //jpgエンコード
const imageminSvgo = require('imagemin-svgo'); //svgエンコード
const imageminOptipng = require('imagemin-pngquant'); //pngエンコード
const imageminGifsicle = require('imagemin-gifsicle'); //gifエンコード
const gulpWatch = require('gulp-watch'); //ファイル監視と実行
const plumber = require('gulp-plumber'); //エラーチェック
const notify = require('gulp-notify'); //エラーをデスクトップに通知
const browserSync = require('browser-sync').create(); //ブラウザシンク
//取得元、出力先のパス
const pathOrigin = {
dest: './dest',
dev: './src'
}
const paths = {
html: {
src: pathOrigin.dev + '/views/*.ejs',
tempSrc: pathOrigin.dev + '/views/**/_*.ejs',
dest: pathOrigin.dest,
map: '/map',
},
styles: {
src: pathOrigin.dev + '/scss/*.scss',
dest: pathOrigin.dest + '/css',
tempSrc: pathOrigin.dev + '/scss/**/_*.scss',
map: '/map',
clearmap: pathOrigin.dest + '/css/map',
},
scripts: {
src: pathOrigin.dev + '/js/*.js',
dest: pathOrigin.dest + '/js',
map: '/map',
clearmap: pathOrigin.dest + '/js/map/',
},
images: {
src: pathOrigin.dev + '/assets/*.{jpg,jpeg,png,svg,gif}',
dest: pathOrigin.dest + '/assets',
}
}
const srcpathAll = [paths.html.src, paths.html.tempSrc, paths.styles.src, paths.styles.tempSrc, paths.scripts.src, paths.images.src];
//画質コントロール
const imageQuality = {
jpg: 60,
png: [0.3, 0.5], //minimum, maximum
svg: 60,
gif: 1, //1 or 3, 1 is default
}
// sass
function stylesFunc() {
return gulp
.src(paths.styles.src, {sourcemaps: true, since: gulp.lastRun(stylesFunc)})
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(postcss([ autoprefixer({
grid: 'autoplace', //gridレイアウトのプレフィックスを有効にする
}) ]))
.pipe(cleanCss())
.pipe(gulp.dest(paths.styles.dest, { sourcemaps: paths.styles.map }));
}
// EJS
function htmlFunc() {
return gulp
.src([paths.html.src, '!' + paths.html.tempSrc], {since: gulp.lastRun(htmlFunc) })
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(ejs())
.pipe(rename({extname:'.html'}))
.pipe(htmlmin({
collapseWhitespace : true, //余白を削除
removeComments : true, //コメントを削除
removeRedundantAttributes: true //default値の属性を削除
}))
.pipe(gulp.dest(paths.html.dest))
}
// JS
function scriptFunc() {
return gulp
.src(paths.scripts.src, { sourcemaps: true })
.pipe(plumber({
errorHandler: notify.onError('Error: <%= error.message %>')
}))
.pipe(babel({
presets: ['@babel/env']
}))
.pipe(uglify())
.pipe (gulp.dest(paths.scripts.dest, { sourcemaps: paths.styles.map, since: gulp.lastRun(scriptFunc)}));
}
//画像処理
function imageFunc() {
return gulp
.src([paths.images.src], {since: gulp.lastRun(imageFunc)})
.pipe(imagemin([
mozjpeg({quality: imageQuality.jpg}),
imagemin.optipng({optimizationLevel: imageQuality.png}),
imagemin.svgo({removeViewBox: false}),
imagemin.gifsicle({optimizationLevel: imageQuality.gif}),
]))
.pipe(gulp.dest(paths.images.dest));
}
// サーバーを立ち上げる
function destServer(done) {
browserSync.init({
server: {
baseDir: pathOrigin.dest,
index : "index.html"
},
reloadOnRestart: true,
});
done();
}
// ブラウザのリロード
function browserReload(done) {
browserSync.reload();
done();
console.log(('reload done'));
}
function removeFile(path, name) {
return del(path.replace(/src\/views/, 'dest').replace('ejs', 'html'));
};
// タスクを監視
function watchFiles() {
//ファイルやディレクトリが削除されたらdest内の同盟ファイルを削除、それ以外ならstylesFuncを実行
gulp.watch(paths.styles.src)
.on('all', (event, path) => {
if (event === 'unlink' || event === 'unlinkDir') {
return del(path.replace(/src\/scss/, paths.css.dest).replace('scss', 'css'));
}
return stylesFunc();
});
gulp.watch(paths.styles.tempSrc, gulp.series(stylesFunc));
gulp.watch(paths.html.src)
.on('all', (event, path) => {
if (event === 'unlink' || event === 'unlinkDir') {
console.log(path);
return del(path.replace(/src\/views/, paths.html.dest).replace('ejs', 'html'));
}
return htmlFunc();
});
gulp.watch(paths.html.tempSrc, gulp.series(htmlFunc));
gulp.watch(paths.scripts.src)
.on('all', (event, path) => {
if (event === 'unlink' || event === 'unlinkDir') {
return del(path.replace(/src\/js/, paths.scripts.dest));
}
return scriptFunc();
});
gulp.watch(paths.images.src)
.on('all', (event, path) => {
if (event === 'unlink' || event === 'unlinkDir') {
return del(path.replace(/src\/assets/, paths.images.dest));
}
return imageFunc();
});
gulp.watch(srcpathAll, gulp.series(browserReload));
}
// mapfile削除
function clearMap() {
return del([paths.styles.clearmap]);
}
// タスクの実行
exports.default = gulp.series(gulp.parallel(stylesFunc, htmlFunc, scriptFunc, imageFunc), gulp.series(destServer, watchFiles));
exports.clearmap = clearMap;
###メモ: ディレクトリ構造
このようにしていますが、変更したい場合はconst = paths
に記載のパスを書き換えてください。
##手順3-2:package.jsonにAutoprefixerの対応ブラウザ範囲を追記
package.jsonのdevDependencies{・・・},の後に、ベンダープレフィックスを対応するブラウザバージョンを指定します。
"browserslist": [
"last 2 versions",
"ie >= 11",
"Android >= 4",
"ios_saf >= 8"
]
##手順3-3:タスクを実行する
ターミナルに次のコマンドを入力することで、タスクが実行されます。
ソースマップは、本番環境には不要なので削除用のタスクを作りました。
//デフォルトタスクの実行
gulp
//ソースマップ削除を実行
gulp clearmap
##gulpfile設定にあたり参考にさせていただいたサイト
gulp公式(英語)
gulp4に移行するためにタスクを書き換えてみた
gulp4の設定方法 - SassやAutoprefixer、ejs、画像の圧縮などを自動化する
#おわりに
もし間違いや、「こっちの方がいいよ!」というのがあれば是非教えてください。
参考にさせていただいたサイトや記事の運営・執筆者さま、ありがとうございました。
2020/5/4追記:以下のパッケージを追加しました。
node-sass-package-importer
gulp-babel
gulp-plumber
gulp-notify