Gulp学习笔记

P1 简介

gulp是基于Nodejs的自动任务运行器, 它能自动化地完成 javascript/coffee/sass/less/html/image/css 等文件的的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。在实现上,她借鉴了Unix操作系统的管道(pipe)思想,前一级的输出,直接变成后一级的输入,使得在操作上非常简单。通过本文,我们将学习如何使用Gulp来改变开发流程,从而使开发更加快速高效。

gulp 和 grunt 非常类似,但相比于 grunt 的频繁 IO 操作,gulp 的流操作,能更快地更便捷地完成构建工作。

P2 安装

可替换淘宝镜像:npm install cnpm -g --registry=https://registry.npm.taobao.org

2.1 全局安装 gulp:

$ npm install -g gulp

查看是否正确安装:命令提示符执行gulp -v,出现版本号version 3.9.1即为正确安装。
如果显示'glup' 不是内部或外部命令,也不是可运行的程序或批处理文件。,请确定你是否打对字,是gulp,而不是glup!!!这里我故意打错字你也发现不了。

2.2 作为项目的开发依赖(devDependencies)安装:

$ npm install --save-dev gulp

P3 Gulp API整理

gulp只有四个API: taskwatchsrc,和 dest

3.1 gulp.task(name[, deps], fn)

name:任务名;
deps:StringArray(可选),一个包含任务列表的数组,这些任务会在你当前任务运行之前完成;
fn:任务操作函数function() {}.
//执行完one, two, three任务后再执行four
gulp.task('four', ['one', 'two', 'three'], function() {
    return gulp.src(path)
        .pipe(someplugin());
    //或其他事
});

3.2 gulp.src(globs[, options])

src方法是指定需要处理的源文件的路径,gulp借鉴了Unix操作系统的管道(pipe)思想,前一级的输出,直接变成后一级的输入,gulp.src返回当前文件流至可用插件;

globs:String 或 Array,需要处理的源文件匹配符路径

**通配符路径匹配: **

  • src/a.js:指定具体文件
  • *:匹配所有文件 src/*.js(包含src下的所有js文件)
  • **:匹配0个或多个子文件夹 src/**/*.js(包含src的0个或多个子文件夹下的js文件);
  • {}:匹配多个属性 src/{a,b}.js(包含a.js和b.js文件) src/*.{jpg,png,gif}(src下的所有jpg/png/gif文件);
  • !:排除文件 !src/a.js(不包含src下的a.js文件);
var gulp = require('gulp'),
    less = require('gulp-less');
 
gulp.task('testLess', function () {
    //gulp.src('less/test/style.less')
    gulp.src(['less/**/*.less','!less/{extend,page}/*.less'])
        .pipe(less())
        .pipe(gulp.dest('./css'));
});
options: (可选) Object,有3个属性buffer、read、base
  • options.bufferBoolean 默认:true 设置为false,将返回file.content的流并且不缓冲文件,处理大文件时非常有用;
  • options.readBoolean 默认:true 设置false,将不执行读取文件操作,返回null;
  • options.baseString 设置输出路径以某个路径的某个组成部分为基础向后拼接,具体看下面示例:
gulp.src('client/js/**/*.js') 
  .pipe(minify())
  .pipe(gulp.dest('build'));  // Writes 'build/somedir/somefile.js'

gulp.src('client/js/**/*.js', { base: 'client' })
  .pipe(minify())
  .pipe(gulp.dest('build'));  // Writes 'build/js/somedir/somefile.js'

异步任务支持
只有当fn接受一个 callback,或者返回一个 promise 或 stream任务 才可以异步执行,且task默认以最大的并发数执行,即gulp 会一次性运行所有的 task 并且不做任何等待。


//接受一个 callback
var exec = require('child_process').exec;
gulp.task('jekyll', function(cb) {
  // 编译 Jekyll
  exec('jekyll build', function(err) {
    if (err) return cb(err); // 返回 error
    cb(); // 完成 task
  });
});

//返回一个 stream
gulp.task('somename', function() {
  var stream = gulp.src('client/**/*.js')
    .pipe(minify())
    .pipe(gulp.dest('build'));
  return stream;
});

//返回一个 promise
var Q = require('q');
gulp.task('somename', function() {
  var deferred = Q.defer();
  // 执行异步的操作
  setTimeout(function() {
    deferred.resolve();
  }, 1);
  return deferred.promise;
});

当然,如果你想要任务按照一定的顺序执行。例如有两个task,"one" 和 "two",在 "one" 中返回一个cb,或stream,promise,让系统知道什么时候它会执行完毕; 在 "two" 中添加提示告诉系统 "two" 需要依赖 "one" 完成,即下面给出的栗子:

var gulp = require('gulp');

// 返回一个 callback,因此系统可以知道它什么时候完成
gulp.task('one', function(cb) {
    // 做一些事 -- 异步的或者其他的
    cb(err); // 如果 err 不是 null 或 undefined,则会停止执行,且注意,这样代表执行失败了
});

// 定义一个所依赖的 task 必须在这个 task 执行之前完成
gulp.task('two', ['one'], function() {
    // 'one' 完成后
});

gulp.task('default', ['one', 'two']);

3.3 gulp.dest(path[, options])

dest方法是指定处理完后文件输出的路径

path:String or Function 指定文件输出路径,或者定义函数返回文件输出路径亦可
options:Object,有2个属性cwd、mode
  • options.cwdString 默认:process.cwd():当前脚本的工作目录的路径 当文件输出路径为相对路径将会用到
  • options.modeString 默认:0777 指定被创建文件夹的权限

3.4 gulp.watch(glob [, opts], tasks)orgulp.watch(glob [, opts, cb])

watch方法是用于监听文件变化,文件一修改就会执行指定的任务

glob: String or StringArray 需要处理的源文件匹配符路径。
opts: Object(可选) 具体参看 gaze
tasks: StringArray 需要执行的任务的名称数组;
cb(event): Function() 每次文件变化执行的回调函数;
  • event.type: String 发生的变动的类型:added, changed 或者 deleted
  • event.path: String 触发了该事件的文件的路径。

P4 新建gulpfile.js文件

说明:gulpfile.js是gulp项目的配置文件,是位于项目根目录的普通js文件(其实将gulpfile.js放入其他文件夹下亦可)

我们将要使用Gulp插件来完成我们以下任务:

  • sass的编译(gulp-sass)
  • 自动添加css前缀(gulp-autoprefixer)
  • 压缩css(gulp-minify-css)
  • js代码校验(gulp-jshint)
  • 合并js文件(gulp-concat)
  • 压缩js代码(gulp-uglify)
  • 压缩图片(gulp-imagemin)
  • 自动刷新页面(gulp-livereload)
  • 图片缓存,只有图片替换了才压缩(gulp-cache)
  • 更改提醒(gulp-notify)
  • 修改文件名(gulp-rename)

安装这些插件需要运行如下命令:

npm install gulp-sass gulp-autoprefixer gulp-minify-css gulp-jshint gulp-concat gulp-uglify gulp-imagemin gulp-notify gulp-rename gulp-livereload gulp-cache --save-dev
//成功安装后在package.json中出现版本信息
{
"devDependencies": {
    "gulp": "^3.9.1",
    "gulp-autoprefixer": "^3.1.1",
    "gulp-cache": "^0.4.6",
    "gulp-concat": "^2.6.1",
    "gulp-imagemin": "^3.2.0",
    "gulp-jshint": "^2.0.4",
    "gulp-livereload": "^3.8.1",
    "gulp-minify-css": "^1.2.4",
    "gulp-notify": "^3.0.0",
    "gulp-rename": "^1.2.2",
    "gulp-sass": "^3.1.0",
    "gulp-uglify": "^2.1.2"
  }
}

更多插件请点这里 gulp.js插件

4.1 加载插件:

// Load plugins
var gulp = require('gulp'),
    sass = require('gulp-sass'),
    autoprefixer = require('gulp-autoprefixer'),
    minifycss = require('gulp-minify-css'),
    jshint = require('gulp-jshint'),
    uglify = require('gulp-uglify'),
    imagemin = require('gulp-imagemin'),
    rename = require('gulp-rename'),
    concat = require('gulp-concat'),
    notify = require('gulp-notify'),
    cache = require('gulp-cache'),
    livereload = require('gulp-livereload');

4.2 建立任务:

4.2.1 编译sass、自动添加css前缀和压缩

首先我们编译sass,添加前缀,保存到我们指定的目录下面,还没结束,我们还要压缩,给文件添加 .min 后缀再输出压缩文件到指定目录,最后提醒任务完成了:

// Styles任务
gulp.task('styles', function() {
    //编译sass
    return gulp.src('stylesheets/main.scss')
        .pipe(sass())
        //添加前缀
        .pipe(autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
        //保存未压缩文件到我们指定的目录下面
        .pipe(gulp.dest('stylesheets'))
        //给文件添加.min后缀
        .pipe(rename({ suffix: '.min' }))
        //压缩样式文件
        .pipe(minifycss())
        //输出压缩文件到指定目录
        .pipe(gulp.dest('assets'))
        //提醒任务完成
        .pipe(notify({ message: 'Styles task complete' }));
});

4.2.2 js代码校验、合并和压缩

// Scripts任务
gulp.task('scripts', function() {
    //js代码校验
    return gulp.src('javascripts/*.js')
        .pipe(jshint())
        .pipe(jshint.reporter('default'))
        //js代码合并
        .pipe(concat('all.js'))
        //给文件添加.min后缀
        .pipe(rename({ suffix: '.min' }))
        //压缩脚本文件
        .pipe(uglify())
        //输出压缩文件到指定目录
        .pipe(gulp.dest('assets'))
        //提醒任务完成
        .pipe(notify({ message: 'Scripts task complete' }));
});

4.2.3 图片压缩

// Images
gulp.task('images', function() {
    return gulp.src('images/*')
        .pipe(cache(imagemin({ 
            optimizationLevel: 3, //类型:Number默认:3取值范围:0-7(优化等级)
            progressive: true, //类型:Boolean 默认:false 无损压缩jpg图片
            interlaced: true, //类型:Boolean 默认:false 隔行扫描gif进行渲染
            multipass: true //类型:Boolean 默认:false 多次优化svg直到完全优化
            })))
        .pipe(gulp.dest('images'))
        .pipe(notify({ message: 'Images task complete' }));
});

4.2.4 事件监听

// Watch
gulp.task('watch', function() {
    // Watch .scss files
    gulp.watch('stylesheets/*.scss', ['styles']);
    // Watch .js files
    gulp.watch('javascripts/*.js', ['scripts']);
    // Watch image files
    gulp.watch('images/*', ['images']);
    // Create LiveReload server
    livereload.listen();
    // Watch any files in assets/, reload on change
    gulp.watch(['assets/*']).on('change', livereload.changed);
});

4.2.5 定义默认任务

栗子里的第二个参数是一个包含任务列表的数组,这些任务会在你当前任务运行之前完成。

gulp.task('default', ['styles', 'scripts', 'images', 'watch'], function() {
    console.log('Everthing is done!');
});

P5 运行gulp

5.1 命令提示符执行

  • 命令提示符执行gulp 任务名称, 如gulp styles
  • 当执行gulp defaultgulp将会调用default任务里的所有任务

5.2 使用WebStorm运行gulp任务

将项目导入WebStorm,右键gulpfile.js 选择“Show Gulp Tasks”打开Gulp窗口,若出现“No task found”,选择右键”Reload tasks”,双击运行即可。

参考文档

一点
gulp API 文档
前端构建工具gulp入门教程1
前端构建工具gulp入门教程2

推荐阅读更多精彩内容