1. 一定要記得 return gulp.src stream
剛開始學習的時候,網路上的教材有兩種寫法。
第一種:無 return
gulp.task("taskName", function() {
gulp.src("檔案")...
}
第二種:有 return
gulp.task("taskName", function() {
// 加了 return 在 gulp src 前面
return gulp.src("檔案")...
}
第一種跟第二種的差別在於,有 return 的我們會知道 tasks 已經結束的時機,而前面沒加 return 的我們不會知道。
gulp 很聰明。在還沒到 concurrency 上限前,預設會同時跑所有需要的 tasks,並且不等待任何返回值。
(簡單來說。By default, gulp task is asynchronous task)
這時,當我們需要有順序的跑 tasks 時,就會因為完成順序不如預期出現錯誤。
範例,我們希望在跑 minify css 之前,先做 scss 編譯。
var sass = require('gulp-ruby-sass');
var minifyCSS = require('gulp-minify-css');
gulp.task('scss', function() {
// syntax change gulp-ruby-sass starting from 1.0.0-alpha
sass('./scss', { style: 'expanded' })
.pipe(gulp.dest('./css/'));
});
// 期望 scss 跑完在跑 minify css,
// ['scss'] 是指定 dependency,styles task 會在 scss 跑完後再跑
gulp.task('styles', ['scss'], function () {
gulp.src('./css/**/*.css') .pipe(minifyCSS())
.pipe(gulp.dest('./dist/css/'));
});
terminal 結果:myBook:gulp-test yvonne$ gulp styles [21:30:25] Using gulpfile ~/work/gulp-test/gulpfile.js [21:30:25] Starting 'scss'... [21:30:25] Finished 'scss' after 5.99 ms // 跑完 scss... [21:30:25] Starting 'styles'... // 開始跑 styles... [21:30:25] Finished 'styles' after 4.11 ms [21:30:26] directory ./ [21:30:26] write ./main.css // 這裏才是 scss 真正編譯完成
雖然結果顯示 styles 是等 scss 跑完後才跑的。
可是後面的 log 卻寫說編譯的 css 是等全部結束後才寫入,結果根本非預期想的那樣。
解法非常簡單,只要加 return 回傳 stream 提示 tasks 結束即可。
var sass = require('gulp-ruby-sass');
var minifyCSS = require('gulp-minify-css');
gulp.task('scss', function() {
return sass('./scss', { style: 'expanded' })
.pipe(gulp.dest('./css/'));
});
// 期望 scss 跑完在跑 minify css,
// ['scss'] 是指定 dependency,styles task 會在 scss 跑完後再跑
gulp.task('styles', ['scss'], function () {
return gulp.src('./css/**/*.css')
.pipe(minifyCSS())
.pipe(gulp.dest('./dist/css/'));
});
myBook:gulp-test yvonne$ gulp styles [21:39:02] Using gulpfile ~/work/gulp-test/gulpfile.js [21:39:02] Starting 'scss'... [21:39:02] directory ./ [21:39:02] write ./main.css // scss 編譯完成! [21:39:03] Finished 'scss' after 249 ms [21:39:03] Starting 'styles'... // styles 才開始跑 [21:39:03] Finished 'styles' after 24 ms
為了避免類似的問題再發生,建議是 return 所有的 gulp stream。
只要沒有特定指定 dependency 的情況下, gulp tasks 都會是採非同步的方式跑。一樣效能很好!
ref:
http://stackoverflow.com/questions/21699146/gulp-js-task-return-on-src
2. 使用外部的 config 管理變數(like grunt)
在 gulp.js 的 github recipes 上有一則如何使用 json 管理 gulp 變數,維持 tasks DRY(Don't Repeat Yourself)。教學用法是把變數寫入在外部的 json 檔案,然後 tasks 可呼叫相同變數。開發者只需要維護 json 裡的變數即可,而不用維護分佈在不同 tasks 的變數。
雖然用 json 維護很方便,可是我個人喜歡用 node 產生 config module,讓變數可有繼承關係。
新增 gulp.config.js
module.exports = function () {
var client = 'root/',
dist = client + 'dist/';
return {
// root
client: client,
scss: {
files: client + '/scss/**/*.scss',
css: {
distPath: dist + 'css/',
name: 'main.css'
}
}
};
};
在 gulpfile.js 記得把 config.js require 進來
var gulp = require('gulp'),
// 需要啟用 config module 的 function
config = require('./gulp.config')();
// print 'root/'
console.log('client path:', config.client);
3. del 取代 rimraf
刪除檔案在 gulp task 是很常見的動作。最常使用方式是當我們需要重新編譯檔案時,先把原先編譯完的舊檔案刪除,避免發生未知的錯誤...
(例如,其實重新編譯的檔案沒有成功,可是因為舊的檔案存在,所以一直以為有成功。然後就 debug 一陣子...)
(或是例如有些套件有 cache 的問題...)
常見用法如下:(scripts 前先清除之前的 js 檔案 )
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var del = require('del');
// pass callback argument 非常重要!!
gulp.task('clean:js', function (cb) {
// 刪除在 js folder 下面全部的檔案
del(['dist/js/**.*'], cb);
});
gulp.task('scripts', ['clean:js'], function() {
gulp.src('./js/**/*.js')
.pipe(uglify())
.pipe(concat('all.min.js'))
.pipe(gulp.dest('./dist/js/'))
});
del 用法很簡單,就是把想要刪除的 path array 放在第一個 argument 即可。(支援 globbing patterns)
然後別忘了要 pass callback,原因跟上面介紹的第一點『 return steam 』原理一樣。當有 dependency 的時候,我們需要讓 task 知道刪除結束的時間點。del 套件在刪除檔案時會呼叫 callback,通知 task dependency 已經結束了~ 這樣才不會刪除跟編譯同時進行喔!