gulp gulp 自动执行任务完任务后怎么退出

gulp的任务的执行是异步的。&所以,当我写完一系列的任务,准备一股脑地执行。
[10:22:54] Starting 'clean'...
[10:22:54] Starting 'compass'...
[10:22:54] Starting 'imagemin'...
[10:22:54] Starting 'style'...
[10:22:54] Starting 'html'...
[10:22:54] Starting 'ftp'...
[10:22:54] Finished 'style' after 88 ms
[10:22:54] Finished 'html' after 86 ms
[10:22:54] Finished 'clean' after 255 ms
[10:22:54] Finished 'ftp' after 549 ms
[10:22:55] Finished 'compass' after 1.5 s
[10:22:56] gulp-imagemin: Minified 15 images (saved 337.01 kB - 30.8%)
[10:22:56] Finished 'imagemin' after 2.46 s
[10:22:56] Starting 'prod'...
[10:22:56] Finished 'prod' after 14 &s
这不是我想要的/(ㄒoㄒ)/~~。任务完全错乱了。ftp上并没有看到我要的文件,因为其他任务还没执行完ftp任务就已经执行了。
我想要的是:('clean', 'compass', [image', 'style', 'html'],'ftp'),圆括号里面串行,中括号里面并行。可以给每个任务写依赖,但是好麻烦,而且有时候多个依赖,依赖与依赖之间依赖。算了。用插件。
var runSequence = require('gulp-run-sequence');
gulp.task('prod', function(cb) {
runSequence('clean', 'compass', ['image', 'style', 'html'], 'ftp', cb);
[15:20:32] Starting 'prod'...
[15:20:32] Starting 'clean'...
[15:20:32] Finished 'clean' after 23 ms
[15:20:32] Starting 'compass'...
[15:20:33] Finished 'compass' after 1.21 s
[15:20:33] Starting 'image'...
[15:20:33] Starting 'style'...
[15:20:33] Starting 'html'...
[15:20:33] Finished 'style' after 49 ms
[15:20:33] Finished 'html' after 55 ms
[15:20:36] gulp-imagemin: Minified 15 images (saved 337.01 kB - 30.8%)
[15:20:36] Finished 'image' after 2.26 s
[15:20:36] Starting 'ftp'...
[15:20:36] Finished 'ftp' after 82 ms
[15:20:36] Finished 'prod' after 3.58 s
【 update:&gulp-run-sequrence插件&已弃用了,可以用gulp-sequence代替&】
也可以用gulp 4.0, 虽然还没正式发布,但是试用了一下,超好。
首先我们要卸了之前装的3.x先,然后重装4.0
然后。就可以这样写我们的任务了
series里的任务是顺序执行的,parallel里的任务是同时执行的。
执行gulp prod看一下效果
[15:36:53] Starting 'prod'...
[15:36:53] Starting 'clean'...
[15:36:54] Finished 'clean' after 24 ms
[15:36:54] Starting 'compass'...
[15:36:55] Finished 'compass' after 1.28 s
[15:36:55] Starting 'parallel'...
[15:36:55] Starting 'image'...
[15:36:55] Starting 'style'...
[15:36:55] Starting 'html'...
[15:36:55] Finished 'style' after 67 ms
[15:36:55] Finished 'html' after 67 ms
[15:36:57] gulp-imagemin: Minified 15 images (saved 337.01 kB - 30.8%)
[15:36:57] Finished 'image' after 2.25 s
[15:36:57] Finished 'parallel' after 2.25 s
[15:36:57] Starting 'ftp'...
[15:36:57] Finished 'ftp' after 63 ms
[15:36:57] Finished 'prod' after 3.62 s
阅读(...) 评论()当前位置:
Gulp学习之委以重任task函数做了什么事情
发布时间:
浏览次数:
gulp.task()函数用来定义一个gulp要执行的任务。其格式如下
gulp.task(name [, deps] [, fn])
该函数有三个参数:name,deps和fn
name 任务的名称,字符串类型,这个参数是必须的。
gulp.task('mytask')
执行该任务
gulp] # gulp mytask
Starting 'mytask'...
Finished 'mytask' after 120 &s
我们定义的这个任务其实什么也没有做。通常情况下是需要有一个回调函数来执行该任务的内容。也就是fn参数
fn 回调函数,要执行的任务都在该回调函数中实现。
gulp.task('mytask',function(){
console.log('mytask');
执行该任务
gulp] # gulp mytask
Starting 'mytask'...
Finished 'mytask' after 360 &s
通过上面两个例子,我们看到,在命令行执行gulp的时候,都需要加上任务名称。如果想省略的话需要使用默认的任务名称&default&
gulp.task('default',function(){
console.log('default');
继续执行上面代码
gulp] # gulp
Starting 'default'...
Finished 'default' after 360 &s
但是一般情况下,我们只是使用default作为一个入口。并不定义实际的内容。其实真正的工作都是由其依赖的任务来做。这就需要使用到参数&deps&。
deps 当前任务执行所依赖的任务,该参数是一个数组。也就是说只有在deps中定义的任务完成的情况下当前任务才会执行。
gulp.task('mytask',function(){
console.log('mytask');
gulp.task('task',function(){
console.log('task');
gulp.task('default',['mytask','task'],function(){
&&& console.log('default');
为了说明其顺序,我们在default中加入一个回调函数。执行代码:
gulp] # gulp Starting 'mytask'... mytask Finished 'mytask' after 309 &s Starting 'task'... task Finished 'task' after 179 &s Starting 'default'... default Finished 'default' after 170 &s
我们知道,js是事件驱动的。所以说所有的这些任务都是异步执行的。它们之间的运行没有先后之分,互相之间是平行的。
gulp.task('mytask',function(){
&&& setTimeout(function(){
&&&&&&& console.log('mytask')
&&& },1000)
gulp.task('default',['mytask'],function(){
&&& console.log('default');
执行结果如下
gulp] # gulp
Starting 'mytask'...
Finished 'mytask' after 983 &s
Starting 'default'... default
Finished 'default' after 168 &s
其中,mytask是在整个程序执行完的1秒以后打印出来的。这种异步的方式导致的一个比较严重的问题就是在实际编译文件过程中,我们会看到程序已经运行完成了,但是我们的文件还在编译。
要解决这个问题就要使程序是同步执行的而不是异步。在官方文档中给出了三种方法:一是在fn中接收一个回调函数作为参数;二是返回一个stream;三是返回一个promise。
gulp.task('mytask',function(){
&&& setTimeout(function(){
&&&&&&& console.log('mytask')
&&& },1000)
我们看这个例子
gulp] # gulp mytask
Starting 'mytask'...
Finished 'mytask' after 1.01 ms
在显示Finished以后才打印的mytask。下面可以通过第一种回调函数的方式来实现同步执行。
gulp.task('mytask',function(cb){
&&& return setTimeout(function(){
&&&&&&& console.log('mytask');
&&&&&&& cb();
&&& },1000);
执行结果如下
gulp] # gulp mytask
Starting 'mytask'...
Finished 'mytask' after 1 s
现在的结果就是我们想要的了。但是,有一点需要注意的是如果我们在fn种接收了一个回调函数作为参数,那么就必须调用该回调函数,否则程序是没法向下执行的。尤其是在有多个依赖任务的程序中,假如在依赖的任务的fn中接收了回调函数为参数,但是并没有调用该回调函数,那这样造成的结果就是程序执行到该任务就结束了。也就是说后续的任务不再被执行。
gulp.task('task',function(cb){
&&& console.log('task');
gulp.task('default',['task'],function(){
&&& console.log('default');
运行该程序发现结果会是惊人的
gulp] # gulp
Starting 'task'...
很明显这段程序没有执行完就停止了。解决的方法就是在task任务中调用cb();
gulp.task('task',function(cb){
&&& console.log('task');
下面回到我们的主线,在说完接收回调函数来使程序达到同步执行后。我们继续看剩下的两种方式。
由于这篇文章尽量不涉及到其它的函数,旨在说明gulp.task的工作方式。所以这里对于剩下的两种方式我们直接使用官网给出的例子
返回 stream
gulp.task('somename', function() {
var stream = gulp.src('client/**/*.js')
.pipe(minify())
.pipe(gulp.dest('build'));
返回 promise
var Q = require('q');
gulp.task('somename', function() {
var deferred = Q.defer();
// do async stuff
setTimeout(function() {
&&&& deferred.resolve();
return deferred.
默认情况下,gulp对于是一次性加载所有的任务,这些任务是并行执行的。我们要想有一个按照一定顺序执行的任务序列,需要做的是:首先为某些任务指定其依赖完成的任务;然后是给任务完成以后通知程序执行下一个任务(通过我们上面介绍的三种方式,可根据实际情况选择)。
同样,我们摘用官网的例子。
var gulp = require('gulp');
// takes in a callback so the engine knows when it'll be done
gulp.task('one', function(cb) {
&&& // do stuff -- async or otherwise
&&& cb(err); // if err is not null and not undefined, the run will stop, and note that it failed
// identifies a dependent task must be complete before this one begins
gulp.task('two', ['one'], function() {
&&& // task 'one' is done now
gulp.task('default', ['one', 'two']);
除非注明转载,本站文章均为原创,欢迎转载,转载请以链接形式注明出处
本文地址:
扫一扫,关注我们哦!
Design By 迹忆gulp构建进阶
9月2日更新:
gulp.src时exclude的细节. 见文章尾部.
9月2日更新: gulp-livereload模块更新了, 升级之后提供的接口的用法发生了变化, 详见模块文档
新兴的task-runner gulp给了开发者除grunt以外的选择,让我们可以更灵活更高效的执行构建.不得不承认gulp有很多grunt拍马不及的优势,连gulpfile都要远远比gruntfile更加node-style.我这个不喜欢配置式的人立刻转了过来, 本篇文章就深入介绍一下gulp的使用, 算是进阶文, 没有任何基础的同学还请先去看一下官网或者其他同学写的入门文.
一句话开始
还是赘述一下入门…就只说下四个API, 流式的处理过程就不说了, 一直pipe下去就行~
gulp.task('taskname', [ taskDep1, taskDep2 ],taskContentFunc) 定义一个任务,声明它的名称, 任务依赖, 和任务内容.
gulp.src( file[s] ) 读取文件,参数为文件路径字符串或数组, 支持通配符.
gulp.dest( destPath ) 写入文件, 作为pipe的一个流程.文件夹不存在时会被自动创建.
gulp.watch(files, [taskDep, taskDep2]) 监控文件,执行任务.
进阶1:dest匹配src
gulp.dest( destPath )会将流中的文件写入到destPath中, 但并不是所有的文件都写在destPath的根目录下, 有的可能是在其下又创建子目录,其中的规则是怎样的呢~?
dest是与src相匹配的. src读取文件路径获取文件,主要有三种情况:
指定的文件:['/foo-1/bar-1.js', '/foo-1/bar-2.js','/foo-2/bar2.js'].
模糊匹配文件名的文件: ['/foo-1/bar-*.js', 'foo-2/bar-*.js'].
模糊匹配路径下的文件: [/*/bar-*.js]
以上三种情况读取的文件, 前两种会写入到destPath的根目录下, 而最后一种情况, 会在destPath下新建foo-1和foo-2文件夹然后写三个文件到相应的文件夹里. 发现规律了吗~? dest会将src”匹配”到的文件路径写出来~(这个匹配必须是纯粹的*匹配, 全匹配, 如果是foo*式的半匹配就不会写文件路径) 第一和第二种匹配到的是指定文件, 第三种匹配到的是符合规则的路径下的文件, 所以会出现上面的情况. 也就是说, 如果想将源文件的路径也dest到目标路径, 那就需要将路径也放在”匹配”中.
下面来看例子: locale目录下有en, zh-cn, zh-tw三个目录,三个文件下各有一个lang.js, 把文件夹也输出到目标路径的做法如下:
$&#106avascript$
gulp.task('locale', function(){
gulp.src( 'locale/*/lang.js' )
.pipe( uglify() )
.pipe( gulp.dest( localeDest ) );
了解这个规律之后,destPath下的目录结构就完全可控了.
gulp中实现src和dest的模块, 深入探查之后发现,可以看成是gulp -& vinyl-fs -&vinyl -& glob-stream -& node-glob的依赖链, 从最底层往上依次来看,node-glob实现的是:
Match files using the patterns the shell uses, like stars and stuff.
然后glob-stream把匹配到的文件流式读取, vinyl构建出gulp生态系统内很关键的File类, 其中的file.relative就是文件匹配时*全匹配出的路径, 上面的例子中就是 [lang-type]/lang.js.
src完成工作, File一直pipe下去, 直到dest时,vinyl-fs有一套写文件的规则: 传入的outFolder 加上 匹配文件时的relative的dirname, 作为目标目录. 整个流程下来,就是完整的src到dest的过程.
对整个流程感兴趣的同学, 可以按照我上面写出的依赖链来读一下相关的源码. 其中除了node-glob是npm作者issaacs写的之外,都是gulp的作者团队实现的, 他们做好好多工作啊.
不明白或者不想太深究的同学,也不必担心.gulp近期内就应该会有”动态dest”的功能出现, 具体参见这个issue: Allow function for outFolder in dest, 持续集成测试已经通过, 就等merge啦~
不懂为什么gulp的版本号跑的怎么这么快, 现在都3.6.3了, 它的前辈还在1.0以下(最新的是0.4.5…)缓步前行.
进阶2: src的玄机 ― 递归和exclude:* and !
gulp.src方法接收的是源文件路径, 可以是string也可以是array.官方给出了src的具体语法和实现模块:
$&#106avascript$
gulp.src(globs[, options])
glob refers to node-glob syntax or it can be a direct file path.
通读一遍node-glob模块的文档后再加以实践,就能掌握gulp.src的玄机,将你想要的文件”吸取”到”管道”中来,然后pipe处理下去:
foo.js指明特定某个文件
*.js匹配当前目录下的所有js文件,不指名扩展名则匹配所有类型
*/*.js匹配所有第一层子文件夹的js文件,第二层请用*/*/.js
**/*.js匹配所有文件夹层次下的js文件, 包括当前目录
上述就是匹配和文件夹深度匹配规则, 当上述两条或者两条以上的规则想结合的话, 匹配到的文件会有一定的读取顺序, 以这样的一个task为例: 为构建一个工具库, 需要将lib文件夹下所有的工具模块小文件合并成一个文件, 其中index.js中通过下面的代码将util暴露给全局:
$&#106avascript$
(function( env ){ env.util = {} })(window);
其他的小模块文件也都使用IIFE来给util添加不同的功能, 如foo.&#106s:
$&#106avascript$
(function(){ window.util.Foo = function(){
// Implementation of Foo
这样的代码结构, 我们可以在构建是保证index.js被最先写入到合并后的文件, 而不必在每个文件里都判断util变量存不存在, 我们让它在文件头,一定存在.要达到这样的目的,我们的文件匹配数组要这样写:
$&#106avascript$
gulp.task( 'build', function(){
gulp.src( [ 'lib/index.js', 'lib/**/*'] )
.pipe( concat( 'chenllosUtil.js' ) )
.pipe( gulp.dest( 'dist/lib/')
这就是优先匹配到的文件优先读取.
下面来讲exclude.
排除的方法就是在文件匹配pattern前加!, 跟.gitignore类似. 但有些地方需要注意:如果任务需要你使用**/*递归匹配, 那么执行exclude也需要递归exclude, 即!exclude/path/**/*.
这个坑是笔者在最近写atom-shell程序时遇到的: 我将atom-shell.app放在了项目目录, 需要构建成OSX的app时就把项目目录中所有的文件都拷贝到atom-shell.app下的contents/resources/app目录下. 所有文件, 当然是要用**/*递归匹配喽~, 后面再跟!./atom-shell.app, 而OSX下的.app文件其实就是文件夹, 递归匹配加非递归exclude, 就造成了其实.app也被读取的状况, 然后就无限引用了… 不过gulp有自己的保护机制, 没有出死循环这样的傻事.
正确的作法是['**/*', '!./atom-shell.app', '!./atom-shell.app/**/*']. 这样就可以把app完全exclude掉了.
by the way, 系统的”最大读取文件数”会限制gulp的执行, 比如**/*将node_module也包含了进来的时候… 具体我是怎么避免这个问题的, 大家可以看我正在写的atom-shell项目的gulpfile.
gulp项目的issue里也有讨论这个问题的, 不少同仁踩了这个坑, 虽然情景不太一样,但都是”exclude文件夹与其下的所有文件”的问题.
gulp的github repo里有这样一个issue:
―: μs: Is it a font issue maybe?
―: http://en.wikipedia.org/wiki/Microsecond
―: Wow, that was fast (pun intended). Thanks!
呃, 其实gulp没有那么那么快, 只是其中的stream处理的这么快而已, 真正的读写文件,还是需要多一点时间的, 这也就是为什么看一系列的task都执行完之后进程还没有退出的原因, 它还在写文件~! 就笔者的经验看来, 从less文件编译出十几个200~2500行的未压缩css文件还是需要个近1秒的时间的( 从敲入gulp less 命令到进程退出), 而输出显示less任务处理的时间只有10ms.文件IO的速度是固定的,task-runner能比拼的只有并发+处理速度+优化减少文件读写.
gulp之所以这么快, 是因为:
使用orchestrator任务系统,最大限度的并发运行多个任务.
每个plugin只做一件事,做好一件事, 提升处理速度
流式处理,极少的文件IO
这里有一篇slide,Build Wars, 构建工具之战, 风趣幽默的介绍了grunt的兴盛和gulp的崛起, 其中也提到了:
Grunt 1.0 alpha uses Orchestrator! (OMG)
Task-runner将来会更加的百家争鸣哦~
进阶3: watch的高级应用 ― liveReload 和 错误处理
gulp中自带的gulp.watch能帮你监控指定的文件, 随之触发执行指定的任务, 或者, 执行一个回调. 注意, 是或者, 不能两者兼具.
gulp.watch(glob [, opts], tasks) or gulp.watch(glob [, opts, cb])
有这么一个模块, 叫做gulp-livereload, 它可以在一个端口(默认为35729)上起一个server, 然后在你的页面上注入一个script标签, 引用它提供的通讯脚本, 在文件发生改变后server通知页面的脚本重新加载这个改变的文件.笔者之前试过好多种类似与livereload(以下简称LR)的插件或工具,这个算是最中意的~
注入脚本的工作可以交给这样的一个名为LiveReload的chrome浏览器扩展程序,这个扩展的图标做的略挫,辨识度较低,开启和没开启的区别就只有中间的小圆点是空心和实心… 当然扩展是死的, 它只会注入对应默认server端口的脚本, 有同时开启两个LR的需求的同学,还是自己定一个端口号然后实例化的时候传给plugin然后在页面中也好script tag吧~
LR有两种用法,作为stream的一环使用或者在watch中使用, 在它的nom页面有详细的介绍, 我就不赘述了. 其中更加灵活的用法肯定是在watch中, 比如监控less编译任务的dest目录下css文件的变化, 然后使页面重新加载某个css文件, 通过lr.changed( filePath )来指定. 不一定非得是变更的文件哦~ ). 具体的用法和方便之处, 你用了就会知道. 在开发传统页面或者SPA时, 都能提升不少的效率.
并没有特别深入的去研究reload的规则, 用它来reload样式表和整个page都是很好用的. 运行机制应该就是LR-server和页面注入的js通讯, 文件发生改变时根据规则进行不同的reload. 从使用经验来看, 如果changed的file在浏览器页面中match不到, 注入的脚本就会重新载入整个页面. 这可以当做一个feature来使用哦, 比如做nodejs开发, 使用ejs或jade或其他模板引擎时, 变更的文件为.ejs或者.jade, LR就会重新载入页面, 正是我想要的结果.
我的下一篇文会讲到jade预编译和LR配合使用的方法, stay tuned.
gulp任务添加错误处理在没有使用watch时还显得没那么重要,但使用了watch之后, 没有错误处理的task在发生错误后会立刻崩溃掉整个gulp进程, 想继续watch?重启~! 这一点程序猿肯定无法忍受, 除非你可以保证每一次的文件保存操作都是可以build通过的… 我这种保存强迫症却对做不到.
经过查阅issue和相关blog, 可以得到如下知识点:
gulp官方推荐的plugin书写规范中, 推荐在发生错误时抛出一个gulp-util的PluginError
这个错误会出现在文件处理stream上
想要捕获这个错误, 在stream上添加on('error', handler)处理函数
找到这些资料之后, 就可以写出初步的带有错误处理的task了:
$&#106avascript$
// 编译less, 压缩
gulp.src( src )
.pipe( less({ compress: true }) )
.on( 'error', function(e){console.log(e)} )
.pipe( gulp.dest(dest) );
这样的错误处理, 我用了一段时间. it works well. 后来在处理jade编译时出现了一些问题, 这里只简单说一下: 如果jade编译任务return stream(为什么return stream下面会讲), 错误发生时errhandler会避免进程crash但是会导致无法继续watch jade compile, 也就是说文件变更后也不会执行任务. 其他任务不受影响.
这些表现上的差异应该是不同插件实现原理不同导致的,因此需要有一个可以处理所有错误的通用方法, 我找到了gulp-plumber, 流式任务体系中的水管工.
$&#106avascript$
var gutil = require( 'gulp-util' )
var plumber = require( 'gulp-plumber' );
function errrHandler( e ){
// 控制台发声,错误时beep一下
gutil.beep();
gutil.log( e );
gulp.task( 'less', function(){
gulp.src( [srcPath] )
// 在处理前注册plumber
.pipe( plumber( errorHandler: errrHandler ) )
.pipe( less() )
.pipe( gulp.dest(destPath) );
现在的错误处理鲁棒性就很好了,至今没有遇见它不能胜任的情况.
进阶3:同步任务/线性任务
gulp比起grunt更加的node-style, 而且其依赖的orchestrator的特性就是最大并发的执行任务, 以上, 在提供了大并发和nodejs异步操作特性的同事,给使用者在gulp中做同步的线性的任务带来了一定的难度.
根据gulp在github上的文档的描述, 有三种方法可以通过任务依赖实现线性的同步的任务.
callback/ return stream / return promise
doc中也给出了三种的范例代码, 但就笔者看来实际可操作的就只有return stream一项, 因为其他的两中方式, 需要的是你准确的知道何时任务结束, 然后callback() 或者 进行promise的revolve. 因此, 笔者的同步任务实践, 只有return stream一种, 下面是范例:
$&#106avascript$
gulp.task( 'coffee', function(){
return gulp.src( coffee Src )
.pipe( coffee() )
.pipe( gulp.dest( coffeeDest ) )
gulp.task( 'uglify', ['coffee'], function(){
return gulp.src( jsSrc )
.pipe( uglify() )
.pipe( jsMinDest );
gulp.task( 'dev', ['coffee'] );
gulp.task( 'default', ['uglify'] );
上述的代码实现了”开发时代码不压缩,部署时执行默认任务进行js压缩”的需求.虽然这个需求也可以通过写两个coffee编译任务来实现, 其中一个在dest前进行uglify, 但是这不该是程序猿的做法, 我们才不要做重复的劳动~!
当然单纯的return stream面对更复杂的task需求时会应付不来,我们还有更好的方式来实现DRY的同时针对不同任务执行不同的流程, 那就是下面要讲的条件判断.
进阶4:条件判断, 让task-runner更懂你
上面提到的需求: 在不增加重复代码的前提下针对不同的command gulp [taskname]执行不同的任务流程. 我们可以通过获取命令的参数然后做判断来实现.
gulp [taskname]最终还是执行的一个nodejs脚本, 所以可以通过process.argv[2]来获取taskname, 如果为undefined那么就是default任务, 有值的话就是其他的任务. 当然也可以用cli比较标准的方式用cmd file ―param的格式来实行命令, 在gulpfile内部来取得参数值, 具体可以看这个讨论.
在取得任务名称后, 和gulpfile中预设好的一个tasklist来做对比, 看看是不是某些特定的任务. 我们仍然以开发和部署来举例. 预设一个这样的tasklist: 如果任务名匹配到, 那么就进行代码压缩,jade/less/coffee编译后的文件都进行压缩, 当然压缩方法不一样.所以我们可以做一个这样的list:
$&#106avascript$
var proTaskList = [undefined, 'all-compress'];
然后用取得的taskname去匹配:
$&#106avascript$
var taskName = process.argv[2];
var isPro = ( proTaskList.indexOf( taskName ) &=0 )? true:
这样就判断出了是否是需要压缩的环境.接下来就是如何做判断了.
gulp-cond模块可以在stream pipe的过程中,判断某个变量的true or false, 将stream导向不同的处理函数:
$&#106avascript$
var cond = require('gulp-cond');
.pipe( cond( boolean, trueHanlder() [, falseHandler() ] ) )
上述的意思是在判断boolean的值后,true时执行trueHandler(), falseHandler()是可选的.
如此一来就可以在jade/less/coffee的编译任务中根据不同的命令行任务进行不同的流导向, 笔者常用的几句判断是这样的, 当然可以在我的github项目(如我的blog项目)中找到全部的gulpfile.
$&#106avascript$
// jade 编译
cond( isPro, jade(), jade({ pretty: true }) )
// less编译 生产时压缩, 开发时将"哪个less文件的哪一行生成了该条css规则"
// 输出在编译好的css文件里
cond( isPro,
less({ compressed: true }),
less({ dumpLineNumbers: 'comments'})
// coffee 编译, 生产时添加uglify流程
.pipe( coffee({ bare: true }) )
.pipe( cond( isPro, uglify() ) )
额外的东西:
使用gulp-changed模块可以大大减少重复编译, 注意extension参数可以告诉模块, 当前任务的源文件和产出文件的扩展名是不同的,把这点考虑进来之后changed模块就能精准的判断编译类的任务的源文件是否较上次有变更了.
尽管gulpfile中是写function来定义和执行任务, 但是一点点配置加上灵活的function会让程序的复用性增强而且更加易读哦.
gulp现在的模块数大约有700+,远远及不上grunt的生态系统. 当然由于gulp的plugin功能性更加专一, 使得模块间相互配合更加方便, 插件的编写也更加的简单.官方给出的gulp-replace模块样例就相当之简单, 赶快给gulp社区贡献自己的一份力量吧~
感谢亲爱的读者看完这篇长文,希望能给你日常的开发带来些许便利. 有任何问题都可以在下面评论中留言, 也可以到我的github上提issue.
9月2日更新:
gulp.src时exclude的细节:
gulp.src匹配, 还有gulp.watch时的匹配, 本质上都是vinyl-fs做的文件系统的匹配. 在写exclude匹配表达式, 也就是那个gulp.src的参数字符串或者字符串数组时, exclude的模式要和匹配的模式一致:
var file2w = ['js/**/*.js', '!js/bundle.js'];
// 可以exclude掉bundle.js
file2w = ['js/**/*.js', '!./js/bundle.js'];
// 无法exclude掉bundle.js
尽管js 和 ./js的含义是一样的, 都是当前目录下的js文件夹, 但是匹配和排除的表达式模式不一致的时候就会无法exclude掉. 这个问题… 我已经提交了issue, 不知道gulp team会怎么回复. 大家可以关注一下这个issue. 渣英语, 勿怪.

我要回帖

更多关于 gulp 任务完成回调 的文章

 

随机推荐