gulp進階-自定義gulp外掛

發表於2016-01-25

gulp已經成為很多專案的標配了,gulp的外掛生態也十分繁榮,截至2015.1.5,npm上已經有10190款gulp外掛供我們使用。我們完全可以傻瓜式地搭起一套構建。

然而,我們經常會遇到一種情況,我們好不容易按照文件傳入對應的引數呼叫了外掛,卻發現結果不如預期,這時候我們就要一點點去排錯,這就要求我們對gulp外掛的工作原理有一定的瞭解。本文以實現一個gulp外掛為例,講解一下gulp外掛是如何工作的。

 

需求描述

通常,我們的構建資源為js/css/html以及其它的一些資原始檔,在開發或釋出階段,js/css會經過合併,壓縮,重新命名等處理步驟。

有些場景下,我們不能確定經過構建後生成js/css的名稱或者數量,如此就不能在HTML檔案中寫死資源的引用地址,那麼該如何實現一個Gulp的外掛用以將最終生成的資原始檔/地址注入到HTML中呢?

假設我們需要實現的外掛是這樣使用方式:

我們通過一個HTML註釋用以宣告需要依賴的資源,InlineResource 是匹配的關鍵詞,”:”做為分割,/*.css$/,/*.js$/ 是宣告要依賴的檔案的正則匹配。

在gulpfile.js我們需要這邊配置:

這裡簡單介紹下其中的一些方法與步驟:

  • gulp.src(‘index.html’) 會讀取檔案系統中當前目錄下的index.html,並生成一個可讀的Stream,用於後續的步驟消費
  • InjectResources(stream) 是我們將要實現的外掛,它接受一個引數用以獲取要注入到HTML中的JS/CSS,此引數應該是一個 Stream 例項,用生成一個Stream例項,用於接收並處理上一步流進來的資料
  • hash(options) 是一個第三方外掛,用於往當前流中的檔名新增md5串,如:gulp-hash
  • gulp.dest(‘dist’) 用於將注入資源後的HTML檔案生成到當前目錄下

我們要關心的是第2點:如何接所有的資原始檔並完成注入?

我們可以將該邏輯分成4個步驟

  1. 獲取所有的js/css資源
  2. 獲取所有的HTML檔案
  3. 定位HTML中的依賴宣告
  4. 匹配所依賴的資源
  5. 生成並注入依賴的資源標籤

在開編之前,我們需要依賴一個重要的第三方庫:map-stream

map-stream 用於獲取當前流中的每一個檔案資料,並且修改資料內容。

步驟1 (JS/CSS資源)

資源流會作為引數的形式傳給InjectResources方法,在此通過一個非同步的例項方法獲取所有的檔案物件,放到一個資源列表:

  • mapStream的處理方法中獲取到的data是由gulp.src生成的vinyl物件,代表了一個檔案
  • 每一個stream都會在接受後丟擲end事件

Note: mapStream的處理方法中的cb方法,第二個引數可以用於替換當前處理的檔案物件

到此,我們就完成了第一步的封裝啦!

步驟2 (HTML檔案)

InjectResources外掛方法會返回一個Writable Stream例項,用於接收並處理流到InjectResources的HTML檔案,mapStream的返回值就是一個writable stream。

此時,mapStream的處理方法拿到的data就是一個HTML檔案物件,接下來進行內容處理。

步驟3 (定位依賴)

我們拿到的data是一個vinyl物件,contents屬性是檔案的內容,型別可能是Buffer也可能是String, 通過toStraing()後可以獲取到字串內容。

所有的依賴宣告都有InlineResource關鍵詞,簡單點的做法,可以通過正則來定位並替換HTML中的資源依賴:

到此,我們完成了資源依賴的定位,下一步將是獲取所依賴的資源用以替換。

步驟4 (依賴匹配)

我們將通過步驟1定義的 getResources 方法獲取所需的資原始檔:

由於 getResources 是非同步方法,因此需要把替換處理邏輯包裹在 getResources 的回撥方法中

根據依賴宣告中的正規表示式,對資源列表一一匹配:

到此只差最後一步,將資源轉換為HTML標籤並注入到HTML中

步驟5 (資源轉換/依賴注入)

接下來的定義一個transform方法,用於將路徑列表轉換為HTML的資源標籤列表,其中引入了 path 模組用於解析獲取檔案路徑的一些資訊,該模組是node內建模組。

最終,我們將標籤列表拼接為一個字串來HTML中的依賴宣告(注入):

到此也就完整地實現了一個擁有基本注入功能的外掛~~~~~~

One More Thing

通過上面實現的示例步驟,可以清楚瞭解到gulp外掛的工作原理。 但要做一個易用/可定製性高的外掛,我們還要繼續完善一下,例如:

  • 比較資源的路徑與HTML的路徑,輸出相對路徑作為預設的標籤資源路徑
  • 提供 sort 選項方法用於修改資源的注入順序
  • 提供 transform 選項方法用於定製標籤中的資源路徑
  • 在依賴宣告中支援 inline 宣告,用以將資源內容內聯到HTML中,例如:

  • 支援名稱空間,用於往同一個資源流中使用多次資源注入的區分,例如:

     
  •  

相關文章