node.jsを使ったタスクランナーgulp。
Sassのコンパイルなどに使用していますが、EJSのコンパイルやAMPページ作成の際にもこれ使えるんじゃない? とgulp.jsを書いてみたので公開してみます。
特にAMPについてはなかなか記事がなかったので、同じようなブログが増えてくれると良いなあと願って……。
(ちなみに、Bootstrap+Sassのみの時はYeomanのweb-appジェネレータを使っています)
目次
EJSファイルは細分化していくうちにごちゃつくので、ejsフォルダにまとめておきます。
ejs-project/
├ package.json
├ gulpfile.js
├ src/
├ assets/
├ fonts/
├ icons/
├ images/
├ ejs/
├ index.ejs
├ js/
├ main.js
├ scss/
├ main.scss
$ npm init
で作ったものにパッケージを入れただけです。
brouserslist
はautoprefixerの設定になります。
{
"name": "project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^9.7.6",
"browser-sync": "^2.26.7",
"css-declaration-sorter": "^5.1.2",
"css-mqpacker": "^7.0.0",
"del": "^5.1.0",
"gulp": "^4.0.2",
"gulp-changed": "^4.0.2",
"gulp-clean-css": "^4.3.0",
"gulp-ejs": "^5.1.0",
"gulp-htmlmin": "^5.0.1",
"gulp-imagemin": "^7.1.0",
"gulp-notify": "^3.2.0",
"gulp-plumber": "^1.2.1",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.0.2",
"gulp-sass-glob": "^1.1.0",
"gulp-sourcemaps": "^2.6.4",
"gulp-uglify-es": "^2.0.0",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0",
"gulp-html-beautify": "^1.0.1"
},
"browserslist": [
"last 2 versions",
"ie >= 11",
"Android >= 7"
]
}
**.min.cssと**.min.jsを用意できるようにはしていますが、あまり使ってないですね……。
htmlminとhtmlbeautifyは同時に使うことはないかも。でもとりあえず載せておきます。
var gulp = require('gulp');
var autoprefixer = require('autoprefixer');
var browserSync = require("browser-sync");
var cssdeclsort = require('css-declaration-sorter'); // プロパティをソートし直す
var changed = require("gulp-changed");
var cleanCSS = require('gulp-clean-css');
var ejs = require("gulp-ejs");
var htmlmin = require("gulp-htmlmin");
var imagemin = require("gulp-imagemin");
var notify = require('gulp-notify'); //エラー発生時にデスクトップ通知する
var plumber = require("gulp-plumber");
var postcss = require('gulp-postcss'); //autoprefixerとセット
var rename = require("gulp-rename");
var sass = require("gulp-sass");
var sassGlob = require('gulp-sass-glob');
var sourcemaps = require('gulp-sourcemaps');
var uglify = require("gulp-uglify-es").default;
var mozjpeg = require('imagemin-mozjpeg');
var mqpacker = require("css-mqpacker");
var pngquant = require('imagemin-pngquant');
var del = require('del');
var htmlbeautify = require("gulp-html-beautify");
// ディレクトリ
var dir = {
src: 'src/',
dest: 'dist/'
}
// scssのコンパイル・圧縮
gulp.task('sass', (done) => {
gulp
.src([dir.src + '/scss/**/*.scss', '!' + dir.src + '/scss/**/_*.scss'])
.pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
.pipe(sassGlob()) //importの読み込みを簡潔にする
.pipe(sass({
outputStyle: 'expanded'
}))
.pipe(postcss([
autoprefixer({
cascade: false
}),
cssdeclsort({
order: 'smacss'
}),
mqpacker()
]))
.pipe(sourcemaps.write())
// .min.cssの書き出し
// .pipe(gulp.dest(dir.dest + '/css'))
// .pipe(cleanCSS({ rebase: false }))
// .pipe(rename({
// extname: '.min.css' //minifyしたファイルの名前変更
// }))
.pipe(gulp.dest(dir.dest + '/css')) //コンパイル後の出力先
done()
});
// ejsのコンパイル・圧縮
gulp.task('ejs', (done) => {
gulp
.src([dir.src + 'ejs/**/*.ejs', '!' + dir.src + 'ejs/**/_*.ejs'])
.pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
.pipe(ejs({}, {}))
.pipe(rename({ extname: ".html" }))
.pipe(htmlmin({
collapseWhitespace: true, // 余白を除去する
removeComments: true // HTMLコメントを除去する
}))
.pipe(htmlbeautify({ // HTMLをきれいにする
indent_size: 2,
indent_with_tabs: false
}))
.pipe(gulp.dest(dir.dest))
done()
});
// JS圧縮
gulp.task('js', (done) => {
gulp
.src([dir.src + 'js/*.js']) // src/js/ 配下の全ファイルを対象
.pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
.pipe(uglify({
compress: true, // 圧縮する
mangle: true, // 変数の難読化を行う
output: {
comments: /^!/ //Licenseコメントの頭にある「*!」を残す
}
}))
// .min.jsの書き出し
// .pipe(gulp.dest(dir.dest + 'js'))
// .pipe(rename({
// extname: '.min.js'
// }))
.pipe(gulp.dest(dir.dest + 'js')) // js 配下に出力する
done()
});
// fonts
gulp.task('fonts', (done) => {
gulp.src([dir.src + 'assets/fonts/**/*'])
.pipe(gulp.dest(dir.dest + 'assets/fonts'))
done()
})
// icons
gulp.task('icons', (done) => {
gulp.src([dir.src + 'assets/icons/**/*'])
.pipe(gulp.dest(dir.dest + 'assets/icons'))
done()
})
// その他コピー
gulp.task('extras', (done) => {
gulp.src([dir.src + '*' , '!' + dir.src + '*.html', '!' + dir.src + 'ejs', '!' + dir.src + 'scss', '!' + dir.src + 'js'], {dot: true})
.pipe(gulp.dest(dir.dest))
done()
})
//圧縮率の定義
var imageminOption = [
pngquant({
quality: [0.7, 0.85],
}),
mozjpeg({
quality: 85
}),
imagemin.gifsicle({
interlaced: false,
optimizationLevel: 1,
colors: 256
}),
imagemin.mozjpeg(),
imagemin.optipng(),
imagemin.svgo()
];
// 画像圧縮
gulp.task('img', function() {
return gulp
.src([dir.src + 'assets/images/**/*.{png,jpg,gif,svg}'])
.pipe(changed(dir.dest + 'assets/images'))
.pipe(imagemin(imageminOption))
.pipe(gulp.dest(dir.dest + 'assets/images'))
});
// Browser Sync
gulp.task('browser-sync', function(done) {
browserSync.init({
server: { //ローカルサーバ
baseDir: dir.dest,
index: "index.html"
}
});
done();
});
//Clean
gulp.task('clean', function(done) {
del.sync(
dir.dest + '**',
'!' + dir.src + 'assets/js/main.js',
'!' + dir.src + 'assets/css/main.css',
);
done();
});
// 監視
gulp.task('watch', function() {
const reload = () => {
browserSync.reload(); //リロード
};
gulp.watch(dir.src + 'scss/**/*.scss').on('change', gulp.series('sass', reload));
gulp.watch(dir.src + 'js/**/*.js').on('change', gulp.series('js', reload));
gulp.watch(dir.src + 'ejs/**/*.ejs').on('change', gulp.series('ejs', reload));
gulp.watch(dir.src + 'assets/images/**/*').on('change', gulp.series('img', reload));
gulp.watch(dir.src + 'assets/fonts/**/*').on('change', gulp.series('fonts', reload));
gulp.watch(dir.src + 'assets/icons/**/*').on('change', gulp.series('icons', reload));
gulp.watch(dir.src + '*').on('change', gulp.series('extras', reload));
});
// gulpコマンドで最初に動作
gulp.task('default',
gulp.series(
'clean',
gulp.parallel(
'ejs',
'sass',
'js',
'img',
'fonts',
'icons',
'extras',
'watch',
'browser-sync'
)
)
);
AMPページのコーディングでSassをコンパイルして容量を測ってからHTMLに差し込んで……の流れが面倒くさかったので、Sassから圧縮したCSSをHTML内のstyleタグに挿入して書き出せるようにしたものです。
amp-project/
├ package.json
├ gulpfile.js
├ src/
├ assets/
├ images/
├ scss/
├ main.scss
├ index.html
<!-- inject:head:css -->〜<!-- endinject -->
の行に圧縮したCSSを挿入したHTMLをdistフォルダに書き出します。
<!doctype html>
<html amp lang="ja">
<head>
<meta charset="utf-8" />
<title>タイトル</title>
<meta name="description" content="ページの説明"/>
<meta name="keywords" content="キーワード"/>
<meta name="viewport" content="width=device-width,initial-scale=1.0,minimum-scale=1.0,user-scalable=no" />
<link rel="canonical" href="ページURL(AMPのみの時はAMPを指定)" />
<link rel="amphtml" href="AMPのページURL(通常版がある時に指定)" />
<script type="application/ld+json">
<!-- 省略 -->
</script>
<!-- inject:head:css -->
<!-- この中にcssが入ります -->
<!-- endinject -->
<script async src="https://cdn.ampproject.org/v0.js"></script>
</head>
<body>
<h1>ページコンテンツ</h1>
</body>
</html>
JSを使わなかったりrenameしなかったりなので、EJS版から不要なものを消します。
{
"name": "project",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^9.7.6",
"browser-sync": "^2.26.7",
"css-declaration-sorter": "^5.1.2",
"del": "^5.1.0",
"gulp": "^4.0.2",
"gulp-changed": "^4.0.2",
"gulp-htmlmin": "^5.0.1",
"gulp-imagemin": "^7.1.0",
"gulp-inject": "^5.0.4",
"gulp-notify": "^3.2.0",
"gulp-plumber": "^1.2.1",
"gulp-postcss": "^8.0.0",
"gulp-sass": "^4.0.2",
"gulp-sass-glob": "^1.1.0",
"imagemin-mozjpeg": "^8.0.0",
"imagemin-pngquant": "^8.0.0"
},
"browserslist": [
"last 2 versions",
"ie >= 11",
"Android >= 7"
]
}
var gulp = require('gulp');
var autoprefixer = require('autoprefixer');
var browserSync = require("browser-sync");
var cssdeclsort = require('css-declaration-sorter'); // プロパティをソートし直す
var changed = require("gulp-changed");
var htmlmin = require("gulp-htmlmin");
var imagemin = require("gulp-imagemin");
var notify = require('gulp-notify'); //エラー発生時にデスクトップ通知する
var plumber = require("gulp-plumber");
var postcss = require('gulp-postcss'); //autoprefixerとセット
var sass = require("gulp-sass");
var sassGlob = require('gulp-sass-glob');
var mozjpeg = require('imagemin-mozjpeg');
var pngquant = require('imagemin-pngquant');
var del = require('del');
var inject = require('gulp-inject');
// ディレクトリ
var dir = {
src: 'src/',
dest: 'dist/'
}
// htmlにcss挿入しdest
gulp.task('inject-css', (done) => {
gulp
.src([dir.src + '*.html'])
.pipe(inject(gulp.src([dir.dest + '/css/main.css']), {
starttag: '<!-- inject:head:{{ext}} -->',
removeTags: true,
transform: function (filePath, file) {
const styleTagStart = '<style amp-custom>';
const styleTagEnd = '</style>';
let styles = file.contents.toString('utf8');
// パスを相対パスに変更
styles = styles.replace('url(../', 'url(');
// sassコンパイル時に生成される行を削除
styles = styles.replace(/\/\*\#\ssourceMappingURL\=.*\.map\s\*\//i, '');
styles = styles.replace(/\@charset \"utf-8\"\;/i, '').trim();
return styleTagStart + styles + styleTagEnd;
}
}))
.pipe(htmlmin({
collapseWhitespace: false, // 余白を除去する
removeComments: false, // HTMLコメントを除去する
minifyCSS: true, // CSS圧縮
}))
.pipe(gulp.dest(dir.dest))
done();
});
// scssのコンパイル・圧縮
gulp.task('sass', (done) => {
gulp
.src([dir.src + 'scss/**/*.scss', '!' + dir.src + 'scss/**/_*.scss'])
.pipe(plumber({ errorHandler: notify.onError("Error: <%= error.message %>") }))
.pipe(sassGlob()) //importの読み込みを簡潔にする
.pipe(sass({
outputStyle: 'expanded'
}))
.pipe(postcss([autoprefixer({
cascade: false
})]))
.pipe(postcss([cssdeclsort({
order: 'smacss'
})]))
.pipe(gulp.dest(dir.dest + '/css')) //コンパイル後の出力先
done()
});
// その他コピー
gulp.task('extras', (done) => {
gulp.src([dir.src + '*' , '!' + dir.src + '*.html', '!' + dir.src + 'ejs', '!' + dir.src + 'scss', '!' + dir.src + 'js'], {dot: true})
.pipe(gulp.dest(dir.dest))
done()
})
//圧縮率の定義
var imageminOption = [
pngquant({
quality: [0.7, 0.85],
}),
mozjpeg({
quality: 85
}),
imagemin.gifsicle({
interlaced: false,
optimizationLevel: 1,
colors: 256
}),
imagemin.mozjpeg(),
imagemin.optipng(),
imagemin.svgo()
];
// 画像圧縮
gulp.task('img', function() {
return gulp
.src([dir.src + 'assets/images/**/*.{png,jpg,gif,svg}'])
.pipe(changed(dir.dest + 'assets/images'))
.pipe(imagemin(imageminOption))
.pipe(gulp.dest(dir.dest + 'assets/images'))
});
// Browser Sync
gulp.task('browser-sync', function(done) {
browserSync.init({
server: { //ローカルサーバ
baseDir: dir.dest,
index: "index.html"
}
});
done();
});
//Clean
gulp.task('clean', function(done) {
del.sync(dir.dest + '/**', '!' + dir.dest);
done();
});
// 監視
gulp.task('watch', function() {
const reload = () => {
browserSync.reload(); //リロード
};
gulp.watch(dir.src + 'scss/**/*.scss').on('change', gulp.series('sass', reload));
gulp.watch(dir.src + 'assets/images/**/*').on('change', gulp.series('img', reload));
gulp.watch(dir.src + '*').on('change', gulp.series('extras', reload));
gulp.watch(dir.src + '**/*.html').on('change', gulp.series('inject-css', reload));
gulp.watch(dir.src + 'scss/**/*.scss').on('change', gulp.series('inject-css', reload));
});
// gulpコマンドで最初に動作
gulp.task('default',
gulp.series(
'clean',
'sass',
'img',
'extras',
'inject-css',
gulp.parallel(
'watch',
'browser-sync',
),
)
);
gulp.task('amp-css',
gulp.series(
'inject-css'
));
CSSの圧縮・挿入が不安だったので、テスト用のamp-cssタスクを残しています。
$gulp amp-css
で動かせます。
$gulp
でコンパイル&Browser Syncを起動します。
なんとなく書いて動けばラッキー的になってるので、もっとしっかり内容を理解して行きたいです。