2

gulp的简单介绍

gulp是一个即grunt后出现的一个前端构建工具,跟grunt相比,gulp的API很少并且很简单,使用nodejs中stream来读取和操作数据,其速度比grunt更快,下面让我们来学习一下如何使用gulp快速构建你的项目。

本文主要介绍

  • gulp的安装和使用

  • gulp的API

  • gulp的常用插件

gulp的安装和使用

1.全局安装gulp

$ npm install --global gulp

2.作为项目依赖安装gulp

$ npm install --save-dev gulp

3.使用gulp

1.在你的文件目录下面建立一个package.jsongulpfile.js的文件。

package.json:此文件被npm用于存储项目的元数据,以便将此项目发布为npm模块。你可以在此文件中列出项目依赖的gulp插件,放置于devDependencies配置字段内;
gulpfile:用来配置或定义任务(task)并加载gulp插件的。

2.安装gulp插件

 $ npm install --save-dev gulp-uglify

--save-dev和--save的区别

如果只写上--save,gulp插件在package.json的dependencies里面保存,而写--save-dev 的话,gulp插件会保存在package.json的devDependencies,这里有关于这两个属性的区别http://www.cnblogs.com/jes_sh...

安装包的两种方式

    $ npm insatll 

devDependencies和dependencies都会安装

  $  npm install --production

只安装dependencies而不安装devDependencies。

  $  npm install packagename

那么只会安装dependencies,而不安装devDependencies。

  $  npm install packagename --dev 

devDependencies和dependencies都会安装

举个例子

我们新建一个文件夹只有package.json文件,执行 会默认读取package.json的
devDependencies和dependencies里面的属性,并且安装devDependencies和dependencies下面的包。
如下所示,会安装gulp和gulp-concat,然后还会读取gulp和gulp-concat
里面的dependencies里面的包,在安装gulp和gulp-concat所依赖的包,但是这个时候并不会安装devDependencies里面的包了

{
  "name": "grunt_test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "dependencies":{
    "gulp": "^3.9.1"
  },
  "devDependencies": {
    "gulp-concat": "^2.6.0"
  },
  "author": "",
  "license": "ISC"
}
$ gulp npm install --save stream-combiner2
{
  "name": "application-name",
  "version": "0.0.1",
  "devDependencies": {
    "del": "^2.2.1",
    "gulp": "^3.9.1",
    "gulp-concat": "^2.6.0",
    "gulp-load-plugins": "^1.2.4",
    "gulp-uglify": "^1.5.4",
    "pump": "^1.0.1"
  },
  "dependencies": {
    "stream-combiner2": "^1.1.1"
  }
}

3.编写gulpfile.js

  var gulp = require('gulp');
    var uglify = require('gulp-uglify');
    gulp.task('uglifyTask', function (cb) {
    return gulp.src('www/**')
        .pipe(uglify())
        .pipe(gulp.dest('dest'));
    })

4.运行task

$ gulp uglifyTask

执行上述命令,就会执行uglifyTask这个task,如果只输入gulp 那么会默认执行default这个任务;

如果gulpfile中没有设置default这个任务,直接执行gulp,就会抛出以下错误

➜$ gulp
[22:40:37] Using gulpfile ~/WebstormProjects/gulp/gulpfile.js
[22:40:37] Task 'default' is not in your gulpfile
[22:40:37] Please check the documentation for proper gulpfile formatting

gulp的API

  • gulp.src(globs,option)

  • gulp.dest(path, options)

  • task(name, deps, fn)

  • gulp.watch(glob , opts, tasks) 或 gulp.watch(glob , opts, cb)

就这四个API是不是特别少,在介绍这些API之前先说一下gulp的工作方式,gulpfile.js充分利用了Node.js的 Streams(流) API ,首先获取到需要的stream,然后可以通过stream的pipe(管道)方法把流导入到你想要的地方,比如Gulp的插件中,经过插件处理后的流又可以继续导入到其他插件中,当然也可以把流写入到文件中。

1.gulp.src(globs,option)

gulp.src就是输出符合所提供的匹配模式(glob)或者匹配模式的数组(array of globs)的文件。 将返回一个流,可以通过管道pipe输入别的gulp插件,内容不是原始的文件流,而是一个虚拟文件对象流(这个是看一篇介绍说的,具体理解不深),我们可以简单理解为读取一个符合globs匹配的文件

globs是文件匹配模式的一个字符串或者一个数组,下面是常用文件匹配模式

  • * 匹配任意数量的字符,但不匹配 /

  • ? 匹配单个字符,但不匹配 /

  • ** 匹配任意数量的字符,包括 /,只要它是路径中唯一的一部分

  • [pattern,pattern1] 匹配方括号中出现的字符中的任意一个,当方括号中第一个字符为^或!时,则表示不匹配方括号中出现的其他字符中的任意一个,类似js正则表达式中的用法

  • ! 在模式的开头用于排除一个匹配模式所匹配的任何文件

下面以一系列例子来加深印象,我的目录结构是这样的

图片描述

'www/*'            匹配  www/a.js www/js
 
'www/?.js'           匹配  www/a.js

'www/**/*.js'        匹配 www/所有二级目录下的js

['www/**/*.js','src/**/*.js'] 匹配 www和src下面的所有的子级目录下面的js文件;

['www/**/*.js','!www/*.js'] 匹配不包含www下面的a.js的所有其他的js文件;

option通过 glob-stream 所传递给 node-glob 的参数,除了 node-glob 和 glob-stream 所支持的参数外,gulp 增加了一些额外的选项参数:

1.options.buffer 类型: Boolean 默认值: true

那么将会以 stream 方式返回 file.contents 而不是文件 buffer 的形式返回;

2.options.read 类型: Boolean 默认值: true

如果该项被设置为 false, 那么 file.contents 会返回空值(null),也就是并不会去读取文件。

3.ptions.base 类型 string

修改 base的值 默认的base的值为通配符开始出现之前那部分路径,如果设置了base值,那么将依照这个base值为基准

 return gulp.src('www/js/**/*.js') //假设匹配上的是www/js/module/a.js,那么base是www/js
        .pipe($.uglify())
        .pipe(gulp.dest('dest')); //dest输出的是 dest/module/a.js 
        
  return gulp.src('www/js/**/*.js',{base:'www'}) //设定了base,那么base是www
        .pipe($.uglify())
        .pipe(gulp.dest('dest')); //dest输出的是 dest/js/module/a.js        

2.gulp.dest(path, options)

path:文件输出的目录,只能是目录地址,如果包含文件名,那么会把文件名也当做目录的一部分建对应的路径,path将替换gulp.src里面的base生成对应的目录存放文件。

gulp.task('uglifyTask', function (cb) {
    return gulp.src('www/js/**/*.js',{base:'www'})
        .pipe($.uglify())
        .pipe($.rename({extname: '.min.js'}))
        .pipe(gulp.dest('dest/uglfy.min.js'));
})

图片描述

options,这个一般不用,这里就不做介绍了,需要了解的可以去官方api进行了解;

3.task(name, deps, fn)

gulp.task 定义一个任务,name类型:string,这个任务的名称;deps类型:array,这个任务依赖的其他任务;fn类型:function 任务的具体操作,有一个参数,是执行完的回调函数cb

这个方法比较简单,这里我主要讲一下执行顺序

/** 压缩 **/
gulp.task('uglifyTask',['clean:dest'],function (cb) {
    console.log('uglifyTask执行')
    return gulp.src('www/js/**/*.js',{base:'www'})
        .pipe($.uglify())
        .pipe($.rename({extname: '.min.js'}))
        .pipe(gulp.dest('dest/uglfy.min.js'));
})
/** 删除 **/
    gulp.task('clean:dest', function (cb) {
         console.log('dest已经执行完毕')
         del([  
            'dest/**/*'
        ])
    })
 $ gulp uglifyTask

上面代码我们会认为首先输出‘dest已经执行完毕’,‘然后输出uglifyTask执行’,结果我们去命令行输出的结果是这个样子滴

➜  gulp gulp uglifyTask
[00:10:54] Using gulpfile ~/WebstormProjects/gulp/gulpfile.js
[00:10:54] Starting 'clean:dest'...
dest已经执行完毕
➜  gulp 

只输出了dest已经执行完毕,这是为什么?

原来,默认的,task 将以最大的并发数执行,也就是说,gulp 会一次性运行所有的 task 并且不做任何等待。如果你想要创建一个序列化的 task 队列,并以特定的顺序执行,你需要在依赖的task里面给出提示,告诉这个task已经执行完毕

提示的三种方式:

  1. 返回一个流

  2. 返回一个promise

  3. 执行回调函数;

了解这些后,上面的我们简单改变一下,就可以让clean执行完后,执行uglify的task;

    gulp.task('clean:dest', function (cb) {
        console.log('dest已经执行完毕')
        return del([  //这是返回一个流
            'dest/**/*'
        ])
        // if (err) return cb(err); // 返回 error
        // cb(); 执行回调函数
        // return Promise.resolve('success'); 返回一个成功的promise
    })

4.gulp.watch(glob , opts, tasks) 或 gulp.watch(glob , opts, cb)

gulp.watch 监视文件,并且可以在文件发生改动时候做一些事情。或者执行一些task

glob跟gulp.src的glob相同,这里就不做介绍了,opts,这个也不经常用API上没有详细的介绍。我们主要讲一下第三个参数为tasks 或者 cb的

当第三个参数是tasks,监听的文件改变的时候会依次执行tasks数组里面的task,并且会返回一个EventEmitter,可以监听EventEmitter的change事件,事件的回调函数会被传入一个名为 event 的对象。这个对象描述了所监控到的变动:
第三个参数是function,那么监听的文件改变的时候,会执行回调函数里面的内容,同样的回调函数也有一个event对象,包含以下属性;

event.type

类型: String

发生的变动的类型:added, changed 或者 deleted。

event.path

类型: String

触发了该事件的文件的路径。   
/** 监听文件变化  tasks**/
var wachEvet=gulp.watch('www/js/**/*.js',['uglifyTask'])
wachEvet.on('change',function(event){
    console.log(event.type+event.path);
})
/** fn **/
gulp.watch('www/js/**/*.js',function(event){
   console.log(event.type+event.path);
})

执行watch 应该建立一个task,然后在命令行里面输入 gulp watch

gulp.task('watch',function(){
    gulp.watch('www/js/**/*.js',function(event){
        console.log(event.type+event.path);
    })
})

gulp的常用插件

gulp的插件比较多,这里我就简单说几个常用到的插件,别的插件我们可以通过这个网址去查询https://www.npmjs.com/browse/...

1.gulp-load-plugins
作用:自动加载gulp插件
地址:https://www.npmjs.com/package/gulp-load-plugins
使用方法:

var $ = require('gulp-load-plugins')();
$.uglify()
// 同上面一样
var uglify = require('gulp-uglify');
uglify()

2.gulp-rename
作用:重命名
地址:https://www.npmjs.com/package...
使用方法:

// 字符串形式
gulp.src("./src/main/text/hello.txt")
  .pipe(rename("main/text/hello.js"))
  .pipe(gulp.dest("./dist")); // ./dist/main/text/hello.js 
 
// 方法 
gulp.src("./src/**/hello.txt")
  .pipe(rename(function (path) {
    path.dirname += "/rname";
    path.basename += "-goodbye";
    path.extname = ".md"
  }))
  .pipe(gulp.dest("./dist")); //base=main/text ./dist/main/text/rname/hello-goodbye.md 
 
// 对象
gulp.src("./src/main/text/hello.txt")
  .pipe(rename({
    dirname: "main/text/rname",
    basename: "aloha",
    prefix: "bonjour-",
    suffix: "-hola",
    extname: ".md"
  }))
  .pipe(gulp.dest("./dist")); // ./dist/main/text/rname/bonjour-aloha-hola.md 

3.gulp-uglify
作用:压缩js代码,这个只是单纯的压缩,并不像grunt一样还能改变名称,所以要配合上面的rename使用
地址:https://www.npmjs.com/package...
使用方法:

gulp.task('uglifyTask',['clean:dest'],function (cb) {
    return gulp.src('www/js/**/*.js',{base:'www'})
        .pipe($.uglify())
        .pipe($.rename({extname: '.min.js'}))
        .pipe(gulp.dest('dest/uglfy.min.js'));
})

4.grunt-concat
作用:合并文件,下面实例会合并一个js,放在dest/concat/all.js
地址:https://www.npmjs.com/package...
使用方法:

gulp.task('concatTask', function (cb) {
    return gulp.src('src/**/*.js')
        .pipe($.concat('concat/all.js'))
        .pipe(gulp.dest('dest'));
})

5.gulp-jshint
作用:语法检查
地址:
使用方法:

gulp.task('jshint',function(){
   return gulp.src('src/**/*.js')
       .pipe($.jshint())
       .pipe($.jshint.reporter('default')) //使用默认的错误提示
      //.pipe(myReporter) 使用map-stream自定义错误信息
})

6.del
作用:删除文件
地址:
使用方法:

gulp.task('clean:dest', function (cb) {
    return del([ 
        'dest/**/*'
    ])
})

7.stream-combiner2
作用:监听流中的错误信息
使用方法:

var combiner = require('stream-combiner2');
var uglify = require('gulp-uglify');
var gulp = require('gulp');

gulp.task('test', function() {
  var combined = combiner.obj([
    gulp.src('bootstrap/js/*.js'),
    uglify(),
    gulp.dest('public/bootstrap')
  ]);

  // 任何在上面的 stream 中发生的错误,都不会抛出,
  // 而是会被监听器捕获
  combined.on('error', console.error.bind(console));

  return combined;
});

8.lazypipe
作用:提出流中的公共部分
网址:http://www.gulpjs.com.cn/docs...

以上是自己的学习记录笔记。


姜艳云
192 声望19 粉丝

引用和评论

0 条评论