認識 Gulp.js — 拆分 Gulp 任務
拆分 Gulp 任務到不同檔案,管理更方便!
概述
當專案架構變複雜,gulpfile.js 裡的公開及私有任務數量也更加龐大,在維護和執行指令時更加不便。
可以將 gulpfile.js 依照功能、專案或其他分類拆分成多個檔案,達到關注點分離 (separation of concerns) 的目的。日後維護和執行會更加輕鬆。
本文會介紹如何拆分 gulpfile.js 檔案及如何執行任務:
- 依功能拆分為多個 gulpfile.js 檔案
- 依專案拆分 gulpfile.js 檔案
依功能拆分為多個 gulpfile.js 檔案
當 Gulp 任務數量眾多,可以將任務拆分成多個模組檔案進行管理,例如將 JavaScript、CSS 和 HTML 的處理任務放在不同模組檔案中。
如此一來,不僅方便新增、修改和搜尋任務。要使用任務時,再將模組檔案的任務集中匯入到相同的 index.js 檔案即可。
接下來,會為範例專案中的 JavaScript、CSS 和 HTML 檔案各自建立壓縮內容的任務。
範例架構如下:
|-- 專案/
|-- index.html
|-- css/
|-- index.css
|-- mobile.css
|-- js/
|-- index.js
- 安裝要使用的套件及外掛程式:
npm install --save-dev gulp gulp-cssnano gulp-htmlmin gulp-uglify
2. 在專案根目錄處建立名為 gulpfile.js 資料夾,在裡面新增 index.js 檔案及其他存放任務的模組檔案。新的專案結構如下:
|-- 專案/
|-- index.html
|-- css/
|-- index.css
|-- mobile.css
|-- js/
|-- index.js
|-- gulpfile.js/
|-- index.js
|-- cssTasks.js
|-- jsTasks.js
|-- htmlTasks.js
對於 Gulp 來說,gulpfile.js 資料夾內的 index.js 檔案等於平常使用的 gulpfile.js 檔案,都是 Gulp 存取任務函式的唯一進入點。
3. 在個別模組檔案內建立壓縮任務。
// cssTasks.js
const {src, dest} = require('gulp')
const cssnano = require('gulp-cssnano')
exports.minifyCSS = function(){
return src('css/*.css')
.pipe(cssnano())
.pipe(dest('dist/css'))
}
// jsTasks.js
const {src, dest} = require('gulp')
const uglify = require('gulp-uglify')
exports.uglifyJS = function(){
return src('js/*.js')
.pipe(uglify())
.pipe(dest('dist/js'))
}
// htmlTasks.js
const {src, dest} = require('gulp')
const htmlmin = require('gulp-htmlmin')
exports.minifyHTML = function(){
return src("*.html")
.pipe(htmlmin({ collapseWhitespace: true }))
.pipe(dest("dist/"));
}
要注意的是,在模組檔案內指定輸入和輸出的檔案路徑時,必須以 gulpfile.js 資料夾為基準點,而不是以模組檔案為基準點。
換句話說,要將 gulpfile.js 資料夾當成是一個單純的檔案,如同未拆分時的 gulpfile.js 檔案。所有的路徑皆從這個資料夾為基準點。
4. 將模組檔案的任務集中匯入至 index.js。在 index.js 中可以直接使用匯入的任務,或是重新進行組裝建立新的任務。
// index.js
const { src, dest, parallel, watch } = require("gulp");
const { minifyCSS } = require("./cssTasks");
const { minifyHTML } = require("./htmlTasks");
const { uglifyJS } = require("./jsTasks");
exports.default = function () {
watch(
["*.html", "js/*.js", "css/*.css"],
{ ignoreInitial: false },
parallel(minifyCSS, minifyHTML, uglifyJS)
);
};
此處利用匯入的任務建立新的監聽任務,再匯出任務以供執行。
5. 在終端機輸入 Gulp 指令就能執行任務:
gulp
依專案拆分 gulpfile.js 檔案
另一種可能的情況是大專案資料夾內有多個小專案資料夾。小專案各自有自己的 Gulp 任務可以使用。所有小專案的Gulp 任務皆集中在大專案根目錄的 gulpfile.js 檔案內。
|-- 大專案/
|-- package.json
|-- gulpfile.js
|-- 小專案1/
|-- index.html
|-- styles.css
|-- index.js
|-- ...
|-- 小專案2/
|-- 小專案3/
要為某個小專案新增、修改任務時,很可能要連帶調整其他小專案的 Gulp 任務,處理起來可能不方便。當小專案數量變多時,更加不輕鬆且容易出錯。
這時候可以將大專案的 gulpfile.js 拆分至各個小專案內。讓小專案有獨立的 gulpfile.js 檔案。
執行小專案時,只需要用到小專案的 gulpfile.js 檔案,不會和其他小專案共用任務。
|-- 大專案/
|-- package.json
|-- 小專案1/
|-- gulpfile.js
|-- index.html
|-- styles.css
|-- index.js
|-- ...
|-- 小專案2/
|-- gulpfile.js
|-- ...
|-- 小專案3/
|-- gulpfile.js
|-- ...
在小專案 gulpfile.js 檔案內撰寫任務的方式,完全與為單一專案撰寫 Gulp 任務的方式相同。
差別在於執行 Gulp 任務的方式。如果要執行某個小專案的 Gulp 任務,有兩種方式:
- 在小專案根目錄執行 Gulp 指令
- 在大專案根目錄執行 Gulp 指令
在小專案根目錄執行 Gulp 任務頗符合直覺。然而,如果同時有多個小專案要執行 Gulp 指令,就得反覆切換資料夾,不是那麼方便。
在大專案根目錄執行 Gulp 指令會是更方便的方式!
Gulp CLI 內建 --gulpfile [檔案路徑]
指令,能夠選擇特定路徑的 gulpfile.js 執行:
查看小專案 1 的 Gulp 任務清單:
gulp --tasks --gulpfile ./小專案1/gulpfile.js
執行小專案 1 的預設任務:
# OK
gulp --gulpfile ./小專案1/gulpfile.js
或
# OK
gulp default --gulpfile ./小專案1/gulpfile.js
執行小專案 1 的 minifyCSS 任務:
gulp minifyCSS --gulpfile ./小專案1/gulpfile.js
此時 Gulp 指令已經變長不少。建議在大專案根目錄的 package.json 中建立對應的 npm 指令,不僅可以集中管理,執行時更方便。
例如為小專案 1 及所有專案建立 build 任務:
// package.json
"scripts": {
"build_p1": "gulp build --gulpfile ./小專案1/gulpfile.js",
"build_all": "gulp build --gulpfile ./小專案1/gulpfile.js & gulp build --gulpfile ./小專案2/gulpfile.js & gulp build --gulpfile ./小專案3/gulpfile.js"
}
只需要在大專案根目錄執行 npm run build_p1
和 npm run build_all
就好,非常精簡!
結論
當 gulpfile.js 檔案的任務數量變多,維護難度增加時,可以依據不同功能或專案將任務拆分至不同檔案。
有兩種建議作法:
- 在 gulpfile.js 資料夾中,將任務拆分為不同的模組檔案,再將模組檔案匯入到相同的 index.js 檔案。
- 將任務拆分至多個 gulpfile.js 檔案,執行任務時指令加上
--gulpfile
和對應的檔案路徑。
這樣一來管理 Gulp 任務時會更加方便,也減少出錯的可能。
參考資料
認識 Gulp.js 系列
想要再多瀏覽 Gulp.js 4 相關教學,別錯過下列文章!