2015年7月5日 星期日

Gulp 介紹 - 更多應用

去年接觸 Gulp.js 後,覺得實在是太好用了,大大的節省前端建置環境的時間跟效能。

所以在公司跟同事分享了初心者如何上手 gulp 跟一些簡單應用。

簡報:


CP 值很高的 Gulp from Yvonne Yu


之後,手頭專案裡的 gulp task 簡單完成後,gulpfile.js 就被我們塵封在專案裡。
除非有另外 task 或 bug,否則很久都沒去維護。
想想有點可惜,gulp 套件那麼多,一定還有好用的套件等我們去發掘。
所以週末就找時間自行摸索了一些網路上其他大家推薦的 gulp 套件~



1. gulp-util

> Utility functions for gulp plugins

utility 顧名思義就是工具箱,裡面包含了很多建立 task 會使用到的工具函式庫。
我覺得最常使用到的 method 應該是 gulp.log()。

用法除了跟 console.log 一樣,還提供上色功能。讓我們可以在一堆 task 中發現錯誤或重要資訊。

ex:
var gutil = require('gulp-util');
// print "Hello Yvonne. How are you?"
gutil.log('Hello', 'Yvonne.', 'How are you?');
// print "ERROR: (紅色的) 發生錯誤"
gutil.log(gutil.colors.red('ERROR:'), '發生錯誤');

顏色表來源:chalk

更多 gulp-util method:
/* 讀到這行,會發出 '逼' 的聲音 */
gutil.beep();
/* 類似 ES6 string template 的用法 */
var info = {name: 'Yvonne', id: 12345};
gutil.template('my name is <%= name %> (<%= id %>)', info)
// print "my name is Yvonne (12345)"
/* empty funtion */
gutil.noop
/* 取得 process.argv ex: type gulp --type dev in termial*/
gutil.env.type === 'dev'

2. gulp-plumber

> Prevent pipe breaking caused by errors from gulp plugins

gulp-plumber 是為了解決 node string pipe 無法中斷發生錯誤時的 task ,所建立的除錯套件。(完整解釋:Error management in gulp

task 執行前,先使用 plumber 套件。

var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var plumber = require('gulp-plumber');

gulp.task('scripts', function() {
    gulp.src('./js/**/*.js')
        .pipe(plumber())
        .pipe(uglify())
        .pipe(concat('all.min.js'))
        .pipe(gulp.dest('./dist/'))
});

這樣就會當錯誤發生的時候,會立即停止 task,並把錯誤訊息整理並印出來。

發生錯誤範例:
MacBook-Pro:gulp-test yvonne$ gulp scripts
[22:25:19] Using gulpfile ~/gulp-test/gulpfile.js
[22:25:19] Starting 'scripts'...
[22:25:19] Finished 'scripts' after 7 ms
[22:25:19] Plumber found unhandled error:
 Error in plugin 'gulp-uglify'
Message:
    /Users/work/gulp-test/js/main.js: Unexpected token: eof (undefined)
Details:
    fileName: /Users/gulp-test/js/main.js
    lineNumber: 3

假如 task 是被 gulp.watch 呼叫的,別忘了在 gulp-plumber 的 handleError 中增加離開的指令。
gulp.task('scripts', function() {
    gulp.src('./js/**/*.js')
        .pipe(plumber({
            handleError: function (err) {
                console.log(err);
                // watch 才會被通知結束 
                this.emit('end');
            }
        }))
        .pipe(uglify())
        .pipe(gulp.dest('./dist/'))
});

3. gulp-if/gulp-filter

> Conditionally run a task

當需要有條件的跑 task 的時候,這兩個利器就非常很好用。

gulp-if 適合 if/if-else condition, 可再搭配 gulp-ignore 使得符合某些條件下可省略某些檔案。
var gulpif = require('gulp-if'),
    uglify = require('gulp-uglify'),
    gutil = require('gulp-util');

// 依照使用者是否輸入 dev 參數判斷
var isDev = !!(gutil.env.dev); 

gulp.task('script', function() {
  gulp.src('./src/*.js')
    // 不是 dev 環境就不跑 uglify
    .pipe(gulpif(!isDev, uglify()))
    .pipe(gulp.dest('./dist/'));
});

gulp-filter 適合比較複雜的篩選過濾,像是需要把篩選過的檔案還原,或是多個不同的篩選條件。

var gulp = require('gulp');
var less = require('gulp-less');
var concat = require('gulp-concat');
var gulpFilter = require('gulp-filter');

gulp.task('default', function () {
    var jsFilter = gulpFilter('**/*.js');
    var lessFilter = gulpFilter('**/*.less');

    return gulp.src('assets/**')
        .pipe(jsFilter)
        .pipe(concat('bundle.js'))
        .pipe(jsFilter.restore())
        .pipe(lessFilter)
        .pipe(less())
        .pipe(lessFilter.restore())
        .pipe(gulp.dest('out/'));
})
copy from gulp-filter

p.s. 有些情況是不需要使用以上方法省略檔案的,只要簡單的在檔案前面加上 ! ,此檔案就會被忽略。
var uglify = require('gulp-uglify');

gulp.task('task', function() {
  // 使用 ! 忽略 node_modules 內全部的檔案
  gulp.src(['./*.js', '!./node_modules/**'])
    .pipe(uglify())
    .pipe(gulp.dest('./dist/'));
});
copy from gulp-if

4. lazypipe

> Lazily create a pipeline out of reusable components. Useful for gulp.

Lazypipe 不是專屬於 gulp 的套件,可是非常適合搭配 gulp 開發 reuse 的程式碼使用。
(撰寫 gulp 的時候也要記得 DRY - Don't repeat yourself)

var lazypipe = require('lazypipe');
var jshint = require('gulp-jshint');
var concat = require('gulp-concat');

// run jsHint
var jsHintTask = lazypipe()
                    .pipe(jshint)
                    .pipe(jshint.reporter);

gulp.task('jsHint', function() {
    return gulp.src('js/main.js').pipe(jsHintTask());
});

// run jsHint then concat files
gulp.task('scripts', function() {
    return gulp.src('js/**/*.js')
        .pipe(jsHintTask())
        .pipe(concat('./js/all.js'))
        .pipe(gulp.dest('./dist'));
});


5. gulp-task-listing
列出 gulpfile.js 裡所有 task 的名稱。
我目前的用法是結合 'help' task,所以其他開發者打 gulp 或是 gulp help 都會列出所有的 task 給開發者看。
var taskListing = require('gulp-task-listing');
gulp.task('help', taskListing);
gulp.task('default', ['help']);

例如會印出:
Main Tasks
------------------------------
    build
    help

Sub Tasks
------------------------------
    build:css
    build:js

Sub Tasks default 會抓取名稱含有 regular expression /[-_:]/.
如需要更改在使用 withFilters 進行調整。

除了套件外,研究的過程還有學習到一些好的應用寫法。
有機會再來寫下一篇~

----
reference:
Useful gulp recipes - Valdelama
JavaScript Build Automation With Gulp.js – Pluralsight Training

沒有留言:

張貼留言