Gulp 結構化最佳實踐

Kayo發表於2016-08-23

在 Gulp 的官方文件中,Gulp 的任務都是寫在 gulpfile.js 這一個檔案中的,如果任務數量不多,這並不會有什麼問題,但當任務數量較多時,會造成程式碼可讀性差,難以維護,多人協作時還會容易造成衝突。因此,更好的處理方式是把 Gulp 的程式碼結構化。

開始結構化

github.com/QMUI/qmui_w…

這是一個前端框架,主要由一個 SASS 方法合集與內建的工作流構成,其中工作流部分提供了一系列的任務用於處理前端流程,並且由於是可配置的框架,需要讀取配置檔案,因此雖然原有的 gulpfile.js 的程式碼並不龐大,但仍然需要進行結構化處理,本文將會詳細說明如何進行結構化處理。

主要的思路是把 gulpfile.js 中的任務分散到獨立的檔案中編寫,然後在 gulpfile.js 中引入這些 task。因此最簡便的方法是把每個 task 單獨寫在獨立的檔案中,以 task 名命名檔名,在 gulpfile.js 中把這些檔案讀取進去,例如:

workflow/task/clean.js

var del = require('del');

gulp.task('clean', '清理多餘檔案(清理內容在 config.json 中配置)', function() {
    // force: true 即允許 del 控制本目錄以外的檔案
    del(common.config.cleanFileType, {force: true});
    console.log(common.plugins.util.colors.green('QMUI Clean: ') + '清理所有的 ' + common.config.cleanFileType + ' 檔案');
});複製程式碼

gulpfile.js

var gulp        = require('gulp'),
    requireDir  = require('require-dir');

// 遍歷目錄,載入 task 程式碼
requireDir('./workflow/task', { recurse: true });

gulp.task('default', ['clean']);複製程式碼

這種方法操作起來比較簡單,同時基本不需要改動原有的程式碼,只需對 gulpfile.js 稍作改動即可。但同時也引入了一些問題,例如,文章開頭說過的,像 QMUI 這類需要讀取公共配置檔案的需求,這裡就無法解決,各個任務中如果需要引入配置表,都需要單獨引入,同時像工具方法這類內容也會重複引入,造成浪費。因此實際上,clean.js 中也不是像上面的例子那樣編寫的,而是採用 module 的方式拆分任務。

Module 形式的結構化

為了避免在子任務檔案中重複引入全域性的配置、外掛依賴和工具方法,更好的方式就是把全域性配置、工具方法以及子任務都拆分成模組,並利用 require 的方式引入模組。

首先,可以先看一下結構化後的目錄結構:

.
├── gulpfile.js
├── package.json
└── workflow
    ├── common.js
    ├── lib.js
    └── task
        ├── clean.js
        ├── compass.js
        ├── include.js
        ├── initProject.js
        ├── merge.js
        ├── readToolMethod.js
        ├── start.js
        ├── version.js
        └── watch.js複製程式碼

接下來以其中幾個檔案為示例:

common.js

// 宣告外掛以及配置檔案的依賴
var plugins     = require('gulp-load-plugins')({
                    rename: {
                      'gulp-file-include': 'include',
                      'gulp-merge-link': 'merge'
                    }
                  }),
    packageInfo = require('../package.json'),
    lib         = require('./lib.js'),
    config      = require('./config.js');;

// 建立 common 物件
var common = {};

common.plugins = plugins;
common.config = config;
common.packageInfo = packageInfo;
common.lib = lib;

module.exports = common;複製程式碼

clean.js

var del = require('del');

module.exports = function(gulp, common) {
  gulp.task('clean', '清理多餘檔案(清理內容在 config.json 中配置)', function() {
    // force: true 即允許 del 控制本目錄以外的檔案
    del(common.config.cleanFileType, {force: true});
    common.plugins.util.log(common.plugins.util.colors.green('QMUI Clean: ') + '清理所有的 ' + common.config.cleanFileType + ' 檔案');
  });
};複製程式碼

gulpfile.js

/**
 * gulpfile.js QMUI Web Gulp 工作流
 */
 var gulp = require('gulp-help')(require('gulp'), {
             description: '展示這個幫助選單',
             hideDepsMessage: true
           }),
    fs = require('fs'),
    common = require('./workflow/common.js');

// 載入任務
var taskPath = 'workflow/task';

fs.readdirSync(taskPath).filter(function (file) {
  return file.match(/js$/); // 排除非 JS 檔案,如 Vim 臨時檔案
}).forEach(function (_file) {
  require('./' + taskPath + '/' + _file)(gulp, common);
});複製程式碼

總結如下:

  • 公共的配置、外掛依賴和工具方法使用一個 common 物件關聯起來,並且封裝成模組
  • 每個子任務封裝成模組,並且可以傳入 gulp 和 common 兩個引數,這樣公共的部分可以複用
  • gulpfile.js 中遍歷任務目錄,對所有子任務都執行 require,所有子任務都在 gulpfile.js 中成功註冊

至此,一個完整的結構化 Gulp 就處理好了,Gulp 的目錄結構變得清晰很多,這時候無論是增加工具方法,增刪子任務,尤其是多人協作時都會方便很多了。

注意事項

除了以上的主要思路,在實踐中一些事項需要注意:

  • 子任務是被 gulpfile.js require 進去的,因此 gulp.srcgulp.dest 的相對目錄關係並不需要修改,依然是以 gulpfile.js 所在目錄為基準。但子任務檔案中 require 檔案是以子任務檔案所在目錄為基準的,如上面的程式碼中 common.js 在引入 package.json 是需要在上層目錄中進行操作 —— packageInfo = require('../package.json')
  • require 當前目錄的模組不能省略 ./,否則無效。
  • 需要有專案中依賴了多個 gulp 的外掛,推薦使用 (gulp-load-plugins)[www.npmjs.com/package/gul…] 外掛管理多個外掛。

相關文章