gulpjs公式ブログでもアナウンスされたように、2018年12月にGulp4が正式にリリースされました。Gulp4未満は数ヶ月後から非推奨になるようです。
「Gulp4」で検索すると、それぞれが違う書き方をしていました。この記事ではgulp.jsの公式ドキュメントを参考に、Gulp3からGulp4に移行するための情報をまとめています。
-
gulp.task()が非推奨になり、関数宣言とexportsが推奨になった - run-sequenceを使った直列・並列処理を、公式APIの
series()とparallel()で実行できるようになった -
gulp.watch()の第二引数が配列から関数名になった - 公式APIに
sourcemapsオプションが追加された - 公式APIの
gulp.lastRun()で差分ビルドができるようになった
gulp.task()が非推奨になり、関数宣言とexportsが推奨になった
Creating Tasksにあるように、関数宣言(function タスク名(){})でプライベートタスクを作成、exportsでパブリックタスクにする書き方へ変わりました。
// 非推奨
gulp.task('task', function() {
...
});
gulp.task('task', () => {
...
});
// 推奨
function task() { // この時点では`gulp`コマンドで実行不可能
...
}
exports.task = task; // `gulp task`で実行可能
Async Completionにあるように、returnを返さない処理の場合はコールバック関数で完了を知らせる必要があります。
基本的なタスクはreturn gulpから始めれば大丈夫です。
// OK
function task() {
return
gulp
.src('')
.pipe()
.pipe(
gulp.dest()
)
);
}
browser-syncではreturnを使っていないので、done()というコールバック関数を実行するようにしました(公式ではcb()となっています)。
// OK
function serve(done) {
browserSync({
server: {
baseDir: '',
},
ghostMode: false,
open: 'external',
notify: false,
});
done();
}
run-sequenceを使った直列・並列処理を、公式APIのseries()とparallel()で実行できるようになった
直列・並列処理はrun-sequenceをインストールしていましたが、直列をseries()で、並列をparallel()で実行できるようになりました。
// run-sequenceを使った場合
const runSequence = require('run-sequence');
gulp.task('default', function() {
runSequence(
['pug', 'sass', 'js'],
'server'
);
});
// `series()`と`parallel()`を使った場合
exports.default = gulp.series(
gulp.parallel(pug, sass, js),
server,
);
gulp.watch()の第二引数が配列から関数名になった
Gulp3では、gulp.watch()の第二引数に配列でタスク名を渡していましたが、Gulp4ではタスクの関数を渡すようになりました。
// Gulp3
gulp.watch([''], ['task']);
// Gulp4
gulp.watch('', task);
gulp.seriesやfunction()を渡すこともできます。
gulp.watch('', gulp.series(task));
gulp.watch('', gulp.parallel(task));
gulp.watch('', function(done) {
done();
});
公式APIにsourcemapsオプションが追加された
sourcemapsはgulp-sourcemapsをインストールしていましたが、gulp.src()とgulp.dest()のoptionsにsourcemapsが追加されました。
// Gulp3
const sourcemaps = require('gulp-sourcemaps');
gulp.task('task', function() {
gulp.src('')
.pipe(sourcemaps.init())
.pipe(sourcemaps.write())
.pipe(gulp.dest(''));
});
// Gulp4
function task() {
return gulp
.src('', {
sourcemaps: true, // init
})
.pipe(dest('',{
sourcemaps: true, // write
}));
}
gulp.dest()でsourcemaps: trueにするとインラインで、パスを渡すと別ファイルで出力されます。たとえばdestのsourcemaps: '.'にすると同階層に出力されます。
公式APIのgulp.lastRun()で差分ビルドができるようになった
差分ビルドにはgulp-changedなどをインストールしていましたが、gulp.src()のsinceオプションにgulp.lastRun()を渡して実行できるようになりました。
// gulp-changedの場合
const changed = require('gulp-changed');
gulp.task('image', function() {
return gulp
.src(src.img)
.pipe(changed(dest.img)) // `gulp.dest()`のパスを渡す
.pipe(imagemin())
.pipe(gulp.dest(dest.img));
);
// `gulp.lastRun()`の場合
function image() {
return gulp
.src(src.img, {
since: lastRun(image) // タスク名を渡す
})
.pipe(imagemin())
.pipe(dest(dest.img));
}
試したときは若干不安定に感じたので、まだ導入はしていません。
名前の衝突に気をつける
書き方が変わって名前の衝突が起こりやすくなっています。
実際にあったのが、browser-syncでの名前の衝突。
// NG
const browserSync = require('browser-sync');
function browserSync(done) { // const browserSyncと衝突している
browserSync({
server: {
baseDir: '',
},
ghostMode: false,
open: 'external',
notify: false,
});
done();
}
browserSyncが衝突していてエラーになりました。
function browserSync(done) {
^
SyntaxError: Identifier 'browserSync' has already been declared
ここではserveというタスク名にすることで回避しました。
// OK
const browserSync = require('browser-sync');
function serve(done) {
browserSync({
server: {
baseDir: '',
},
ghostMode: false,
open: 'external',
notify: false,
});
done();
}
公式ドキュメントで以下のように名前付きインポートをしている箇所があります。
const { src, dest, lastRun, watch } = require('gulp');
const gulp = require('gulp');だとgulp.src()のようにしますが、名前付きインポートを使うとsrc()のようにできます。
ただ、src・destはパスを変数化するときに使ったり、watchはタスク名に使っていることも多いです。名前付きインポートは使わない方がベターなのかなと思いました。
Gulp4に移行したgulpfile.jsは以下のリンクを参考にしてください。