Gulp打包工具

前端打包工具有很多款,从早期雅虎的Ant到现在的Webpack,期间的迭代变化的差别之大,如同Java到JavaScript,除了名字有点一样,几乎就是两门完全不同的语言。公司项目主要用Gulp和Webpack,本篇先整理一下Gulp

如果你用过Grunt,可能觉得Gulp有点莫名其妙,Grunt前辈社区完善,插件成千上万,弄出个Gulp干什么?我个人感觉在未来的前端开发中一切都将是JS,因此即便是配置工具,Gulp用JS代码实现的策略优于Grunt的半JS半配置的策略。而且Gulp用流的方式进行文件处理,通过管道将多个任务和操作连接在一起,全程只有一个IO过程,最后的结果直接写入硬盘。因此打包流程更加清晰,没有中间临时文件,速度更快。注意,不要轻视“速度更快”这个评价,打包的时间越短越好,快1秒也能提高前端工程师的效率,做前端的都懂的…

  • 安装和执行
  • 插件引入
  • task
  • 数据流
  • watch

安装和执行

安装很简单:

npm install --global gulp

安装之后,在工程目录下新建一个名为gulpfile.js的文件:

var gulp = require('gulp');
gulp.task('default', function() {
    ……
});

这样在目录下执行gulp就能自动执行上面定义的default方法。

插件引入

作为一款流程的打包工具,社区丰富的插件库是必不可少的。除了var gulp=require(‘gulp’);是一定要引入的外,其他的插件根据需要自行引入。例如gulpfile.js的头部可能是这样的:

var gulp = require('gulp');
var del = require('del');
var less = require('gulp-less');
var base64 = require('gulp-base64');
var tpl2mod = require('gulp-tpl2mod');
var extReplace = require('gulp-ext-replace');

从上面代码就能看出,Gulp完全遵守CommonJS的规范,无论是前端页面工程师,还是后端Node工程师都可以零基础立马上手。这可能也是Gulp能取代Grunt的一个原因。

task

引入插件后,就需要建立一个个子任务来执行插件。task函数的原型:

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

第一个参数是task名。第二个参数可选,是个任务列表array,这些任务会在运行当前任务之前运行,例如:

gulp.task('default', ['css', 'image', 'ejs', 'babel']);

需要注意的是,你需要确保array里的任务都在当前任务开始前被运行完毕。如果array里的任务是同步方法,那就没没什么好担心的,Gulp会确保顺序依次执行。但如果array里的任务是异步方法,需要确保是否使用了一个callback,或返回一个promise或stream。

第三个参数fn里定义了任务需要执行的操作。

数据流
如果你熟悉Java,那么IO数据流这个策略应该非常熟了。Gulp通过串联起来的的小函数来传递数据,这些函数会对数据进行修改,然后把修改后的数据传递给下一个函数。src函数的原型:

gulp.src(globs[, options])

该函数将输出匹配globs的文件。输出的文件可以用pipe输入到别的插件中,形成一串数据流。

第一个参数globs,可以是string也可以是array,是一些常用的正则表达式,例如:

js/sample.js    //精确匹配文件
js/*.js              //匹配js目录下的所有js文件
js/**/*.js        //匹配js目录及其子目录下所有后缀为.js的文件
!js/sample.js   //从匹配结果中去除js/sample.js文件
 *.+(js|css)      //匹配根目录下所有后缀为.js或者.css的文件

//例如:匹配js目录及其子目录下所有js文件,但需要去除后缀为.min.js的文件
gulp.src(['js/**/*.js', '!js/**/*.min.js'])

更多高级语法,请仔细阅读node-glob语法。

第二个参数options可选,除了支持node-globglob-stream的参数外,还支持一些Gulp的额外的参数。例如:

options.buffer:如果设为false,将会以stream方式返回file.contents而不是文件buffer的形式。这在处理一些大文件的时候将会很有用。

options.read:如果设为false, 那么file.contents会返回null,这样就不会去读取文件

options.base:string型的值,将会被加在glob之前。例如下面两段代码唯一的区别是,上面这段没有options.base,而下面这段加上了options.base,导致结果路径有区别:

gulp.src('client/js/**/*.js') 
  .pipe(minify())
  .pipe(gulp.dest('build')); 
 //匹配client/js/somedir/somefile.js并且将base解析为client/js/,因此结果 写入build/somedir/somefile.js

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

数据流的结果通过dest函数输出,原型:

gulp.dest(path[, options])

第一个参数是文件被输出的路径,路径是相对路径,当然相对路径也可根据上面的options.base来计算。第二个参数options可选,具体可以参照Linux的文件系统操作命令:

options.cwd:默认值process.cwd()。输出目录的 cwd 参数,只在所给的输出目录是相对路径时候有效。

options.mode:默认值0777,用以定义所有在输出目录中所创建的目录的权限。

看一个Babel解码ES6的例子:

gulp.task('babel', function () {
    return gulp.src('./javascript/**/*.js')
        .pipe(babel({
            presets: [
                'es2015',
                'stage-0'
            ],
            plugins: [
                'transform-runtime',
                'syntax-async-functions',
                'transform-class-properties',
                'transform-decorators-legacy'
            ]
        }))
        .pipe(gulp.dest('./js'));
});

最后,Gulp及其插件使用的流是vinyl文件对象流(stream或buffer),和普通的文件流(chunk)还是有区别的。因此在使用Gulp时,如果pipe出现Streaming not supported。可能是因为传给Gulp及其插件的是普通文件流(例如Node里fs.createReadStream(‘app.js’).pipe(uglify()))。可以用vinyl-source-stream转换工具转一下就行了。

watch

Gulp可以监视文件的修改,功能类似于Jade里的-w参数,当文件有变动时,执行回调函数。Watch有两种原型:

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

第一种原型:第一个参数glob用于指定哪些文件需要被监视,语法参数数据流不赘述。第二个参数opts可选,参照gaze。第三个参数tasks用于指定当被监视的文件有改动时,执行哪些task。watch函数始终会返回一个EventEmitter 来发射change 事件。例如:

var watcher = gulp.watch('js/**/*.js', ['uglify','reload']);
watcher.on('change', function(event) {
  console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});

第二种原型:和第一种的区别是,第三个参数不是task数组,而是自定义回调函数。回调函数的参数是event对象,你可以从该参数中获取到event.type(被监视的文件发生的变化类型added,changed, deleted)和event.path(触发该事件的文件的路径)例如:

gulp.watch('js/**/*.js', function(event) {
  console.log('File ' + event.path + ' was ' + event.type + ', running tasks...');
});

总结

技术总是在发展,从实际使用下来的经验看,Gulp确实比Grunt更快,代码更少更易读。Gulp能火多久不清楚,目前来看,还是项目的一个比较理想的打包工具。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容