Gulp4.0入门指南

安装

Gulp官网javascript

gulp4.0分离了cli和核心部分,因此须要分别安装这两个包,另外对环境要求以下:css

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做为入口便可。html

Task

task分为两种:java

  • 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此任务已完成。node

// 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时输出文件,因此很是快速高效。webpack

gulp提供了src及dest方法分别来进行文件读入、输出操做,同时提供了pipe管道方法来链式执行其余操做。web

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提供的匹配规则来处理。c#

  • "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

使用插件和其余库

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: '.' }));

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之类)自己都是相对较简单的,这才是它们该有的样子,自己就很复杂了,我才懒得用。可是在使用过程当中,我以为有两个难点:

  • 如何制定一套合理、可配置、可以真正提高咱们工做效率的构建流程
  • 如何在须要某个功能时,可以快速找到最合适的那个插件,且可以快速使用

最后,本人才疏学浅,有不妥之处,欢迎指正。

相关文章
相关标签/搜索