歡迎來我的部落格閱讀:《Gulp 基礎與原理》
Gulp 概述
Gulp 是基於 NodeJS 的專案,一個用作自動化構建的工具,業界一般用來建造前端的工作流。
它的核心原理其實很簡單,最主要是透過各種 Transform Stream 來實現檔案的處理,然後再進行輸出。Transform Streams 是 NodeJS Stream 的一種,是可讀又可寫的,它會對傳給它的物件做一些轉換的操作。
檔案輸入 → Gulp 外掛處理 → 檔案輸出
原則上,gulp 可以針對檔案做任何有趣、有創造力事情。
而自動化構建,只是大家主要比較喜歡使用的方向。
Gulp 的特點:
- 自動化 - Gulp 為你的工作流而服務,自動執行那些費事費力任務。
- 平臺透明 - Gulp 被整合到各種 IDE 中,並且除了 NodeJS 之外,其他如 PHP、.NET、Java 平臺都可以使用 Gulp。
- 強大生態系統 - 你可以使用 npm 上 2000+ 的外掛來構造你的工作流。
- 簡單 - Gulp 只提供幾個 API,這可以很快地學習和上手。
使用 Gulp
安裝
$ npm install gulp-cli -g // 全域性安裝 Gulp 命令列工具
$ npm install gulp -D // 在專案中,作為 devDependencies 依賴安裝 gulp複製程式碼
Gulpfile.js
在使用 CLI 工具的時候,會執行該檔案,它是一個可執行的 NodeJS 檔案。原理上,你可以在裡面執行任何 NodeJS 程式碼,然後透過呼叫 gulp 提供的 API,來執行 gulp 任務。gulpfile.js
檔案一般都會放在專案的根目錄中。
一個使用 gulp-babel 外掛來支援 es2015 語法的案例:
const gulp = require('gulp');
const babel = require('gulp-babel');
gulp.task('default', () => {
gulp.src('src/app.js')
.pipe(babel({
presets: ['es2015']
}))
.pipe(gulp.dest('dist'));
});複製程式碼
基本概念與原理
瞭解這些概念,對於瞭解 Gulp 的工作原理,和 API 的使用是很有幫助的。
認識 Glob
Glob 是一種用來匹配路徑與檔案的模式。有點類似於正規表示式,但是語法又有點差異。
這種模式,被廣泛用於命令列、Shell 等場景,大家熟悉的 .gitignore
檔案也是使用這種模式。
各大語言都有對於 Glob 的實現,例如 Go 和 PHP 的 Glob
函式,Python 中的 glob
模組。
而 NodeJS 的實現是 minimatch, 而在 Gulp 原始碼中,就用了對 minimatch 進行封裝的 node-glob 模組。
Gulp 的 API gulp.watch
和 gulp.src
都有用到 Glob 來匹配對應的路徑和檔案。
下面是部分語法:
*
匹配該路徑段中 0 個或多個任意字元,
如:js/*.js
, 匹配 js 目錄下的所有 js 檔案?
匹配該路徑段中 1 個任意字元,
如:js/?.js
,匹配 js 目錄下所有名字只有 1 個字的 js[...]
匹配該路徑段中在指定範圍內字元,
如:js/a[0-3].js
,匹配 js 目錄下 a 開頭,第二個字元為 0-3 之間( 包括0和3 )的 js( a03.js不能被匹配到 )!(pattern|pattern|pattern)
匹配除所給出的模型以外的情況,
如:js/!(a|b).js
,匹配 js 目錄下名字中不包含 a ,也不包含 b 的所有檔案.?(pattern|pattern|pattern)
匹配所給出的模型中的 0 個或任意 1 個,
如:js/?(a|a2|b).js
, 匹配 js 目錄下 a.js , a2.js , b.js+(pattern|pattern|pattern)
匹配所給出的模型中的 1 個或者多個,
如:js/+(a|a1|b).js
, 匹配 js 目錄下 a.js , a1.js , b.js , 或者 a, a1, b 這幾個字元的組合的 js , 比如 ab.js*(pattern|pattern|pattern)
匹配所給出的模型中的 0 個或多個或任意個的組合.
如:js/*(a|a1|b).js
,匹配 js 目錄下 a.js, a1.js, b.js 或者 a, a1, b這幾個字元的組合的 js , 比如 ab.js@(pattern|pat*|pat?erN)
匹配所給出的模型中的任意 1 個,
如:js/@(a|a1|b)
, 匹配 js 目錄下的 a.js, a1.js, b.js**
與*
一樣可以匹配任何內容,但**
不僅匹配路徑中的某一段,而且可以匹配a/b/c
這樣帶有/
的內容,所以,它還可以匹配子資料夾下的檔案.
如:js/**/*.js
,匹配 js 目錄下及子資料夾中所有的 js 檔案。
更多 Glob 的知識和語法,可以參考:
Glob - Wiki
Glob Primer
認識 Vinyl
Vinyl 是 Gulp 自創的一種用來描述一個虛擬檔案的類,其中主要包括檔案的內容和檔案的路徑兩大資訊。vinyl 模組,只是提供了一個類,而實現卻交由 vinyl-fs
Vinyl-fs,它主要的工作是接受 glob 模式的引數,然後讀取匹配的檔案。然後利用 Vinyl 製作一個 Transform Stream,稱為 Vinyl Stream 物件,並返回。
在 Gulp 中的 API gulp.src
、gulp.watch
、gulp.dest
都返回一個 Vinyl Stream 例項物件。Vinyl Stream 例項之間可以透過管道( vinyl1.pipe(vinyl2)
)的形式來互相傳輸資料。
從 Gulp 的 原始碼 中也能看出,這三個 API 都是由 vinyl-fs 提供全部的實現。
再一點是,從這兩個模組的實現來看,Gulp 是把檔案內容以 Buffer 的形式讀到記憶體中,然後再進行處理的。
認識 Orchestrator
Orchestartor,為 gulp.task
提供了全部實現,這可以從 原始碼 中看出。
它為 Gulp 提供了任務相關的功能,包括任務註冊、任務執行以及相對應的任務進度、錯誤監控等功能。
Orchestartor 模組,只提供了一個 Orchestartor 類,該類的例項維護著一個 tasks 陣列,該陣列的內容就是一個我們使用 gulp.task
時註冊的函式列表,以及函式的依賴和名字。
透過 原始碼 中,可以看到 tasks 的資料結構:
...
this.tasks[name] = {
fn: fn, // 任務的函式體
dep: dep, // 任務所依賴的其他任務名稱
name: name // 該任務的名稱
};
...複製程式碼
Gulp 核心 API
- gulp.src:獲取檔案
- gulp.dest:寫入檔案
- gulp.tasks:註冊任務
- gulp.watch:監控檔案的改動
gulp.src
gulp.src( globs [, options] )
接收一個 globs 模式的物件,可以是 Array 或者 String,返回一個 Vinyl Stream 例項。
而 options 有下面的值:
- buffer - Boolean, 控制
file.contents
是返回 buffer 還是 stream。 - read - Boolean,控制是否讀取檔案,如果 false,則
file.contents
為null
- base - String,控制 glob 的 base,預設值是 glob 所有表示式的前置,例如
client/js/**/*.js
, base 值就為client/js/
。而 glob 在儲存輸出路徑的時候,取的是 base 之後的路徑。所以可以透過該值,來進行輸出路徑的改寫。
gulp.dest
gulp.dest( path [, options] )
接收輸出路徑,返回一個 Vinyl Stream 例項。
而 options 有以下的值:
- cwd - String, 預設值
process.pwd()
,輸出目錄的 cwd 引數,只在所給的輸出目錄是相對路徑時候有效。 - mode - String,八進位制許可權字元,用以定義所有在輸出目錄中所建立的目錄的許可權。
gulp.task
gulp.task( name [, deps ], fn )
定義一個使用 Orchestrator 實現的任務(task)。
引數的描述如下:
- name - 任務名稱
- deps - 是當前定義的任務需要依賴的其他任務,為一個陣列。當前定義的任務會在所有依賴的任務執行完畢後才開始執行。如果沒有依賴,則可省略這個引數
- fn - 為任務函式,我們把任務要執行的程式碼都寫在裡面。該引數也是可選的。
gulp.watch
gulp.watch( glob [, opts ], tasks )
orgulp.watch( glob [, opts, cb ] )
用來監視檔案的變化,當檔案發生變化後,我們可以利用它來執行相應的任務。
各引數的描述如下:
- glob - 為要監視的檔案 Glob 匹配模式。
- opts - 為一個可選的配置物件。
- tasks - 為檔案變化後要執行的任務,為一個陣列
常用外掛
- gulp-load-plugins:自動載入
package.json
中的 gulp 外掛 - gulp-rename: 重新命名
- gulp-uglify:檔案壓縮
- gulp-concat:檔案合併
- gulp-less:編譯 less
- gulp-sass:編譯 sass
- gulp-clean-css:壓縮 CSS 檔案
- gulp-htmlmin:壓縮 HTML 檔案
- gulp-babel: 使用 babel 編譯 JS 檔案
- gulp-jshint:jshint 檢查
- gulp-imagemin:壓縮jpg、png、gif等圖片
- gulp-livereload:當程式碼變化時,它可以幫我們自動重新整理頁面
更多外掛,可以搜尋官方外掛庫。