Gulp4.0入門指南

閱讀原文javascript

安裝

Gulp官網css

gulp4.0分離了cli和核心部分,因此須要分別安裝這兩個包,另外對環境要求以下:html

node >= 8.11.1
npm >= 5.6.0
npx >= 9.7.1
複製代碼
  • 全局安裝gulp-cli
npm i -g gulp-cli
複製代碼
  • 本地安裝gulp
npm i -D gulp
複製代碼
  • 查看版本號
$ gulp -v

# 輸出

CLI version: 2.2.0
Local version: 4.0.2
複製代碼

配置文件

在項目根目錄建立gulpfile.js文件(若是使用ts或者babel,也可用gulpfile.tsgulpfile.babel.js分別代替),此文件即gulp會默認讀取的配置文件,咱們能夠在裏面配置須要的task。 若是task較多或者較複雜,能夠建立gulpfile.js目錄,在目錄中拆分task爲多個文件,只要保證該目錄下有個index.js做爲入口便可。java

Task

task分爲兩種:node

  • Private tasks:配置文件中的一個function,僅能在該文件中使用
  • Public tasks:將Private tasks導出,能夠供gulp命令執行
const { series, parallel } = require('gulp');
// Private tasks
function clean(cb) {
  // body omitted
  cb();
}
// Private tasks
function build(cb) {
  // body omitted
  cb();
}

exports.build = build; // Public tasks, 執行gulp build
exports.default = series(clean, parallel(css, javascript)); // Public tasks, 執行gulp
複製代碼

注意: 在task中,操做完成時,咱們必需要經過cb()或者return的方式來告知gulp此任務已完成。webpack

// cb
function clean(cb) {
  del(['dist]); cb(); }); // return function minifyjs() { return src('src/**/*.js') .pipe(minify()) .pipe(dest('dist')); }); function promiseTask() { return new Promise(function(resolve, reject) { // body omitted resolve(); }); }); 複製代碼

運行task

gulp <export task name> 
gulp // 導出爲default的task能夠直接運行gulp
複製代碼

組合task

  • series:序列(順序執行)
// task1執行完再執行task2
exports.taskName = series(task1, task2)
複製代碼
  • parallel:並行(同時執行)
// task1和task2同時執行
exports.taskName = parallel(task1, task2)
複製代碼
  • 混用:
exports.taskName = series(clean, parallel(css, javascript))
複製代碼

輸入與輸出

gulp借鑑了Unix的管道(pipe)思想,處理文件採用流的方式,前一步的輸出做爲後一步的輸入,中途不會在磁盤寫入文件,僅在dest時輸出文件,因此很是快速高效。web

gulp提供了src及dest方法分別來進行文件讀入、輸出操做,同時提供了pipe管道方法來鏈式執行其餘操做。正則表達式

const { src, dest } = require('gulp');

// 將src目錄下的全部js輸出到output目錄
exports.default = function() {
  return src('src/*.js')
    .pipe(dest('output/'));
}
複製代碼

若是咱們想在中途添加文件能夠採用以下方式:npm

const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');

exports.default = function() {
  return src('src/*.js')
    .pipe(uglify())
    .pipe(src('vendor/*.js')) // 添加文件
    .pipe(dest('output/'));
}
複製代碼

固然咱們也能夠進行屢次輸出:gulp

const { src, dest } = require('gulp');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');

exports.default = function() {
  return src('src/*.js')
    .pipe(babel())
    .pipe(dest('temp/'))
    .pipe(uglify())
    .pipe(dest('output/'));
}
複製代碼

文件匹配

每每咱們在使用src方法的時候須要輸入多個或者一類文件,而不只僅是某個具體的文件,這時咱們就可使用gulp提供的匹配規則來處理。

  • "src/file.js":單個文件
  • ["src/file1,src/file2.js"]:多個文件
  • *: 全部文件
src('src/*.js') // src自身目錄全部的js文件,不含後代文件夾中
src('src/a*c.js') 
複製代碼
  • **:0或者多個文件夾
src('src/**/*.js') // src目錄全部的js文件,含後代文件夾中的
複製代碼
  • {}:多個屬性
src('src/*.{jpg,png,gif}') // src自身目錄下的全部jpg、png和gif文件
複製代碼
  • !:排除
src(['**/*.js', '!node_modules/**']) // 全部的js文件,可是node_modules下的除外
複製代碼

注意:src 接收的文件匹配字符串會順序解釋,因此你能夠寫成這樣 gulp.src(['.js', '!b.js', 'bad.js'])(排除全部以 b 開頭的 JS 文件可是除了 bad.js

匹配符                             說明
*                               匹配文件路徑中的0個或多個字符,但不會匹配路徑分割符,
                              除非分隔符出如今末尾

**                              匹配路徑的0個會多個目錄 及子目錄 須要單獨出現,
                              即他左右不能有其餘的東西了若是出如今末尾,也能匹配文件

?                              匹配文件路徑中的一個字符(不能匹配路徑分割符/)

[...]                           匹配方括號中 出現字符的任意一個,當方括號中第一個字符爲^或!時,
                              則表示不匹配方括號中出現字符中的任意一個,
                              相似於js中正則表達式中的用法

!(pattern|pattern|pattern)      匹配任何與括號中給定的任意模式都不匹配
?(pattern|pattern|pattern)     匹配括號中給定的任意模式0次或1次
+(pattern|pattern|pattern)      匹配括號中的至少一次
*(pattern|pattern|pattern)      匹配括號中給定的任意模式0次或屢次
@(pattern|pattern|pattern)      匹配括號中 給定的任意模式一次
複製代碼

使用插件和其餘庫

gulp推薦每一個插件應該只專一的作一小部分工做,而後經過pipe將它們鏈接起來,就能夠完成咱們須要作的事情。

const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');
const rename = require('gulp-rename');

exports.default = function() {
  return src('src/*.js')
    // The gulp-uglify plugin won't update the filename .pipe(uglify()) // So use gulp-rename to change the extension .pipe(rename({ extname: '.min.js' })) .pipe(dest('output/')); } 複製代碼

固然,除了插件,咱們也可使用其餘庫:

const del = require('delete');

exports.default = function(cb) {
  // Use the `delete` module directly, instead of using gulp-rimraf
  del(['output/*.js'], cb);
}
複製代碼

最後也能夠藉助through2插件使用內聯方式自行處理,也能夠利用次through2進行gulp插件開發:

const { src, dest } = require('gulp');
const uglify = require('uglify-js');
const through2 = require('through2');

exports.default = function() {
  return src('src/*.js')
    // Instead of using gulp-uglify, you can create an inline plugin
    .pipe(through2.obj(function(file, _, cb) {
      if (file.isBuffer()) {
        const code = uglify.minify(file.contents.toString())
        file.contents = Buffer.from(code)
      }
      cb(null, file);
    }))
    .pipe(dest('output/'));
}
複製代碼

監聽文件

咱們可使用watch方法來監聽文件的改動,以便在改動時執行相應的處理任務。

const { watch, series } = require('gulp');

function clean(cb) {
  // body omitted
  cb();
}

function javascript(cb) {
  // body omitted
  cb();
}

function css(cb) {
  // body omitted
  cb();
}

exports.default = function() {
  watch('src/*.css', css);
  watch('src/*.js', series(clean, javascript));
};
複製代碼

API

src(globs, [options]):輸入

  • globs[string|array]: 要處理文件的路徑匹配規則
  • options:配置項,點擊查看詳情
const { src, dest } = require('gulp');

function copy() {
  return src('input/*.js', { sourcemaps: true })
    .pipe(dest('output/'));
}
複製代碼

dest(directory, [options]):輸出

const { src, dest } = require('gulp');
const uglify = require('gulp-uglify');

src('input/**/*.js', { sourcemaps: true })
  .pipe(uglify())
  .pipe(dest('output/', { sourcemaps: '.' }));
複製代碼

注意: dest的路徑默認是基於當前路徑,並非輸入文件的路徑,若是須要輸出到輸入文件的相對路徑,可使用gulp-rename插件來實現。如我要將全部目錄下的scss目錄中的scss文件輸出到scss同目錄的css文件中:

src('./SCOs/**/scss/*.scss')
.pipe(sass())
.pipe(rename(path=> path.dirname += '../../css'))
.pipe(dest('./SCOs'));
複製代碼

series(...tasks):順序執行多個任務

  • tasks[function|string]:任務名或者function
const { series } = require('gulp');

function javascript(cb) {
  // body omitted
  cb();
}

function css(cb) {
  // body omitted
  cb();
}

exports.build = series(javascript, css);
複製代碼

parallel(...tasks):多個任務同時執行

  • tasks[function|string]:任務名或者function
const { parallel } = require('gulp');

function javascript(cb) {
  // body omitted
  cb();
}

function css(cb) {
  // body omitted
  cb();
}

exports.build = parallel(javascript, css);
複製代碼

watch(globs, [options], [task]):文件監聽

  • globs[string|array]: 要監聽的文件
  • options:配置項,點擊查看詳情
  • task[function|string]:要執行的任務或操做
const { watch } = require('gulp');

watch(['input/*.js', '!input/something.js'], function(cb) {
  // body omitted
  cb();
});
複製代碼

監聽方法會返回一共實例,該實例提供了以下幾個方法:

watcher.on(eventName, eventHandler)

  • eventName[string]:事件名稱,能夠是add, addDir, change, unlink, unlinkDir, ready, error, or all
  • eventHandler[function]:事件處理函數,該函數接收path和stats兩個參數。
const { watch } = require('gulp');

const watcher = watch(['input/*.js']);

watcher.on('change', function(path, stats) {
  console.log(`File ${path} was changed`);
});

watcher.on('add', function(path, stats) {
  console.log(`File ${path} was added`);
});

watcher.on('unlink', function(path, stats) {
  console.log(`File ${path} was removed`);
});

watcher.close();
複製代碼

watcher.close():關閉文件監聽器

watcher.add(globs):添加文件到監聽器

  • globs[string|array]: 要添加的文件

watcher.unwatch(globs):移除監聽器中的文件

  • globs[string|array]: 要移除的文件

task([taskName], taskFunction):定義任務(4.0推薦使用function替代此方法)

  • taskName[string]:任務名稱
  • taskFunction[function]:處理函數
const { task } = require('gulp');

task('build', function(cb) {
  // body omitted
  cb();
});

const build = task('build');
複製代碼

lastRun(task, [precision]):獲取任務最後運行完成的時間戳

  • task[function|string]:指定獲取的任務
  • precision[number]:精度,默認1000 可以使用此方法進行增量編譯。
const { src, dest, lastRun, watch } = require('gulp');
const imagemin = require('gulp-imagemin');

function images() {
  return src('src/images/**/*.jpg', { since: lastRun(images) })
    .pipe(imagemin())
    .pipe(dest('build/img/'));
}

exports.default = function() {
  watch('src/images/**/*.jpg', images);
};
複製代碼

tree([options]):獲取任務依賴關係

  • options[object]:deep默認爲false,只會返回頂級任務,若是爲true,則會返回整個任務樹。
gulp.tree({ deep: true })
複製代碼

Vinyl:一個文件描述器,本身開發插件可能會用到

具體的用法見gulp源碼解析(二)—— vinyl-fs

我經常使用的api就這些,其餘的api能夠自行查看官方文檔。

經常使用插件

  • gulp-clean:用於清理;
  • gulp-notify:用於打印消息文本;
  • gulp-rename:用於修更名字;
  • gulp-concat:用於合併文件;
  • gulp-zip:用於生成一個zip壓縮包;
  • gulp-minify-css:用於壓縮css;
  • gulp-autoprefixer:用於給css添加前綴;
  • gulp-imagemin:用於給圖片進行優化;
  • gulp-uglify:用於壓縮js;
  • amd-optimize:用於amd模塊引用編譯;
  • gulp-import-css:若是css文件是經過import導入的可使用此插件進行合併優化;
  • gulp-rev-replace:用於替換;
  • gulp-useref:引入使用build標記,進行替換;
  • gulp-rev:生成md5文件名;
  • gulp-filter:對文件進行過濾;
  • gulp-header:壓縮以後將註釋寫入到文件的頭部
  • gulp-if:進行邏輯判斷
  • gulp-size:獲取文件大小
  • gulp-less:編譯less文件
  • gulp-sass:編譯sass文件
  • gulp-file-include:對文件進行引入
  • gulp-sourcemaps:生成map文件
  • gulp-livereload:自動刷新
  • gulp-clean-css:css壓縮
  • browserSync:啓動server並啓動熱更新
  • gulp-plumber : 監測工做流,報錯,防止遇到錯誤時直接退出gulp
  • gulp-rev : 文件名添加版本號
  • gulp-css-spritesmith:根據css文件自動生成雪碧圖

若是要查找gulp插件,通常有兩個地方:

總結:

gulp自己其實很是簡單,提供的api不多,可是簡潔夠用。在瞭解這些api後,你可能以爲最複雜的仍是瞭解各插件的用法。

其實,構建工具(gulp、webpack之類)自己都是相對較簡單的,這纔是它們該有的樣子,自己就很複雜了,我才懶得用。可是在使用過程當中,我以爲有兩個難點:

  • 如何制定一套合理、可配置、可以真正提高咱們工做效率的構建流程
  • 如何在須要某個功能時,可以快速找到最合適的那個插件,且可以快速使用

最後,本人才疏學淺,有不妥之處,歡迎指正。

相關文章
相關標籤/搜索