Gulp挑战Grunt,背后的哲学
2015-07-30 08:41
363 查看
http://www.jianshu.com/p/3779f708f5d7/
[按:网上介绍Gulp和Grunt安装使用的文章很多,甚少比较二者的思路,连官方文档都语焉不详。我在此做一个粗陋的对比,希望能提纲挈领,加深读者对这两个工具的理解。]
做过点儿正经开发的同学都知道,构建工具必不可少。C时代的Make、Java的Ant、Ruby的Rake……没有这些工具,一遍遍地点选输入,准烦死你。
在前端和Node JS的开发中,最普及的构建工具就是Grunt。它的功能说来简单,就是管理一系列的Task。大部分的Task都是第三方的插件,安装好对应的NPM包,再
Grunt的配置文件
配置每个Task,包括文件从哪里,到哪里去,还有一些处理的选项
自己写一些简单的Task,把第三方插件提供的Task组合起来
别看这两个事儿,轻轻松松几百行出来了。每个Task的配置,各有各的规矩,还牵扯到插件间的配合。反正我从seed库开始做新项目的时候,基本不敢改原来的Gruntfile,很多用不上的功能也搁那儿。留意了一下很多开源项目的Gruntfile,也都臃肿杂乱,好不到哪儿去。
Gruntfile维护起来那么困难,有几个原因:
配置和运行分离
程序员都知道,变量的声明和使用挨在一起,最方便理解和修改。但Gruntfile里,配置Task和调用它们的地方离得很远,极大地增加了心智负担。
每个插件做的事太多
每个Task的结果必须写到磁盘文件,另一个Task再读,损害性能倒是小事,更麻烦的是让整个过程变复杂了。
就像一个个小作坊,来料加工又返回给客户,这中间的沟通成本、出错机会都大大增加。
配置项过多
做事多了,配置项自然也多。至少输入和输出的位置得配吧。每个插件的配置规则还不尽相同。用每个插件,都得去学习一番。
Gulp应运而生。
恐怕没几个IT人不知道Unix管道的概念。前一级的输出,直接变成后一级的输入。把简单的工具组合起来,优雅地解决复杂的问题。听起来那么熟悉呢?是的,Gulp就把这种思维用在构建过程中。
Gulp基于Node JS的一个机制,叫做stream,有点类似C++中的stream。在Node中,文件访问、输入输出、HTTP连接,都是stream。Gulp的每个插件从stream中读取输入,做一些处理,再输出到stream中。
每个插件不是拿来独立使用的。相反,它专注于完成单一职责。只有把合适的插件组合起来,才能完成具体的Task。引用官方的例子,看看一个典型的Task长什么样(略有删减):
配置呢?不需要了。是不是行云流水,一气呵成?
那我们再回头来看看前面Grunt的几个问题,Gulp是怎么解决的:
配置和运行分离
code over configuration,直接就在调用的地方配置。
每个插件做的事太多
单一职责,依靠组合来发挥作用。就像一条自动化生产线,上一道工序的产出直接交给下一步,效率不要太高。
配置项过多
既然大家都遵循同一个协议,很多配置就不需要了。
放大了看,Gulp像是一个非常贴近领域模型的DSL,而Grunt更像万能的XML。哪个好用,无需多说。在我们***DSL时,也有参考意义。
最后,举一个Grunt很别扭,Gulp却能优雅解决的例子。
做前端开发会用到一个功能叫
比较一下grunt-usemin和gulp-usemin各自README的长度,就能看出区别。
先从html文件中收集需要处理的js和css,传给后续的一堆任务
它本身并不知道在实际中会调用哪些其它Task,只能用一些hack,支持固定的几个Task。而上面的每个Task,都有自己的配置项。要把这些配置项都列出来,实在太长了。
真正执行,更新html文件里的js和css引用。
而
当前,Gulp的社区还远不如Grunt成熟,有些功能的插件,Gulp可能就没有。这其实不算很大的劣势,只要足够好用,追上来很快。而且,写一个Gulp插件要比相应的Grunt插件短小得多!
[按:网上介绍Gulp和Grunt安装使用的文章很多,甚少比较二者的思路,连官方文档都语焉不详。我在此做一个粗陋的对比,希望能提纲挈领,加深读者对这两个工具的理解。]
做过点儿正经开发的同学都知道,构建工具必不可少。C时代的Make、Java的Ant、Ruby的Rake……没有这些工具,一遍遍地点选输入,准烦死你。
在前端和Node JS的开发中,最普及的构建工具就是Grunt。它的功能说来简单,就是管理一系列的Task。大部分的Task都是第三方的插件,安装好对应的NPM包,再
loadNpmTasks就可以用了。
Grunt的配置文件
Gruntfile,主要包含两部分:
配置每个Task,包括文件从哪里,到哪里去,还有一些处理的选项
自己写一些简单的Task,把第三方插件提供的Task组合起来
别看这两个事儿,轻轻松松几百行出来了。每个Task的配置,各有各的规矩,还牵扯到插件间的配合。反正我从seed库开始做新项目的时候,基本不敢改原来的Gruntfile,很多用不上的功能也搁那儿。留意了一下很多开源项目的Gruntfile,也都臃肿杂乱,好不到哪儿去。
Gruntfile维护起来那么困难,有几个原因:
配置和运行分离
程序员都知道,变量的声明和使用挨在一起,最方便理解和修改。但Gruntfile里,配置Task和调用它们的地方离得很远,极大地增加了心智负担。
每个插件做的事太多
每个Task的结果必须写到磁盘文件,另一个Task再读,损害性能倒是小事,更麻烦的是让整个过程变复杂了。
就像一个个小作坊,来料加工又返回给客户,这中间的沟通成本、出错机会都大大增加。
配置项过多
做事多了,配置项自然也多。至少输入和输出的位置得配吧。每个插件的配置规则还不尽相同。用每个插件,都得去学习一番。
Gulp应运而生。
恐怕没几个IT人不知道Unix管道的概念。前一级的输出,直接变成后一级的输入。把简单的工具组合起来,优雅地解决复杂的问题。听起来那么熟悉呢?是的,Gulp就把这种思维用在构建过程中。
Gulp基于Node JS的一个机制,叫做stream,有点类似C++中的stream。在Node中,文件访问、输入输出、HTTP连接,都是stream。Gulp的每个插件从stream中读取输入,做一些处理,再输出到stream中。
每个插件不是拿来独立使用的。相反,它专注于完成单一职责。只有把合适的插件组合起来,才能完成具体的Task。引用官方的例子,看看一个典型的Task长什么样(略有删减):
[code]var paths = { scripts: ['client/js/**/*.coffee', '!client/external/**/*.coffee'] }; gulp.task('scripts', ['clean'], function() { // 可以依赖于其它task return gulp.src(paths.scripts) // 指定输入 .pipe(coffee()) // 环节一 .pipe(uglify()) // 环节二 .pipe(concat('all.min.js')) // 环节三 .pipe(gulp.dest('build/js')); // 指定输出 });
配置呢?不需要了。是不是行云流水,一气呵成?
那我们再回头来看看前面Grunt的几个问题,Gulp是怎么解决的:
配置和运行分离
code over configuration,直接就在调用的地方配置。
每个插件做的事太多
单一职责,依靠组合来发挥作用。就像一条自动化生产线,上一道工序的产出直接交给下一步,效率不要太高。
配置项过多
既然大家都遵循同一个协议,很多配置就不需要了。
放大了看,Gulp像是一个非常贴近领域模型的DSL,而Grunt更像万能的XML。哪个好用,无需多说。在我们***DSL时,也有参考意义。
最后,举一个Grunt很别扭,Gulp却能优雅解决的例子。
做前端开发会用到一个功能叫
usemin。我们HTML中会引用到很多css和js文件。发布时,这些文件要合并、压缩、混淆,最后生成一两个文件。为了让修改过的代码绕过浏览器的缓存机制,要根据文件内容hash出文件名。html文件里就要引用这些新的文件名。
比较一下grunt-usemin和gulp-usemin各自README的长度,就能看出区别。
[code]grunt.registerTask('build', [ 'useminPrepare', // 准备 'concat', 'cssmin', 'uglify', 'filerev', 'usemin' // 执行 ]);
grunt-usemin分成两步:
先从html文件中收集需要处理的js和css,传给后续的一堆任务
它本身并不知道在实际中会调用哪些其它Task,只能用一些hack,支持固定的几个Task。而上面的每个Task,都有自己的配置项。要把这些配置项都列出来,实在太长了。
真正执行,更新html文件里的js和css引用。
而
gulp-usemin就干净得多,没有丝毫多余的东西:
[code]gulp.task('usemin', function() { gulp.src('./*.html') .pipe(usemin({ css: [minifyCss(), 'concat'], html: [minifyHtml({empty: true})], js: [uglify(), rev()] })) .pipe(gulp.dest('build/')); });
usemin不需要有
minifyCss、
minifyHtml、
uglify和
rev这几个插件的任何知识,只要把对应的内容从stream丢出去就好。在用这些插件组装task时才需要关心。
当前,Gulp的社区还远不如Grunt成熟,有些功能的插件,Gulp可能就没有。这其实不算很大的劣势,只要足够好用,追上来很快。而且,写一个Gulp插件要比相应的Grunt插件短小得多!
相关文章推荐
- Spring讲解-----------测试
- sphinx ---rotate 运行机制
- iOS UI01_UIView
- Windows 操作系统与 .NET Framework
- 并查集详解,不会的同学可以来瞅瞅,转载的,不过加了一些自己的理解。
- session之退出登陆
- 求的数组中不定元素的和为一个定制的所有可能
- 用Kettle的一套流程完成对整个数据库迁移 - - ITeye技术网站
- 有用的第三方库
- 教你快速高效接入SDK——Unity统一接入渠道SDK(Android篇)
- Java 迭代器以及和for循环的比较
- 连载三之OC面向对象编程中的继承
- 原生js与jQuery实现简单的tab切换特效对比
- iOS完整学习路线图
- 浅谈 ZipArchive 类
- Spring讲解------------零配置
- 电平标准
- arcgis AO 和AE的区别
- 解决Unity的 The file 'MemoryStream' is corrupted! Remove it and launch 崩溃问题
- Windows下的cd命令