Gulp探究折腾之路(I)2
原文链接:http://www.jianshu.com/p/9768a4dc7cf7
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
前言: gulp
是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器;她不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成;使用她,我们不仅可以很愉快的编写代码,而且大大提高我们的工作效率。相比于grunt
的频繁 IO 操作,gulp的流操作,能更快地更便捷地完成构建工作。此处仅记录初步折腾中所遇点滴以及待解决的点。
Gulp折腾之初探
折腾之战略上的藐视
回过头看Gulp的折腾历程,使用还是非常简易的。所以战略上一定要藐视"她";当然战术上要给予足够的重视。毕竟要依赖她以及其他各种插件and编辑器等实现前端工程化,组件化,模块化,便捷化是一个蛮复杂的过程。总之,折腾伊始需要自信就好,折腾过程带着耐心就好。譬如,想借助gulp压缩美化下js代码,写如下代码于gulpfile.js即可:
var gulp = require('gulp'),
uglify = require('gulp-uglify');
var gNeedDealJsFile = './js/*.js'; //javascrip代码存放路径
var outPut = "./build/"; //指定输出文件存放目录
gulp.task('scripts', function() {
return gulp.src(gNeedDealJsFile)
.pipe(uglify())
.pipe(rename({
suffix: '.min'
}))
.pipe(gulp.dest(outPut));
});
在gulpfile.js同级目录运行gulp scripts
即可;PS:当然前提是您已经安装了nodejs,并且使用npm安装了代码中需要的插件gulp
和gulp-uglify
与本地。
摒弃了gulp.run()
gulp的API很简单,常用的也就几个:watch, task, dest, src;目前已经摒弃了run方法。
//创建Default Task:注册缺省任务
gulp.task('default', function() {
gulp.run('jshint', 'scripts');
gulp.watch(workSpace, function() {
gulp.run('jshint', 'scripts');
})
});
gulp.run() has been deprecated. Use task dependencies or gulp.watch task triggering instead.
可以根据gulp.task(name[, deps], fn)特性写法替代之。deps:(Array)一个包含任务列表的数组,这些任务会在你当前任务运行之前完成。
注意: 你的任务是否在这些前置依赖的任务完成之前运行了?请一定要确保你所依赖的任务列表中的任务都使用了正确的异步执行方式:使用一个 callback,或者返回一个 promise 或 stream。
//创建Default Task:注册缺省任务
gulp.task('default', ['jshint' , 'scripts', 'watch']);
折腾gulp.src()
Gulp使用node-glob来从你指定的glob里面获取文件,这里列举下面的例子来阐述,方便大家理解:
js/app.js 精确匹配文件
js/.js 仅匹配js目录下的所有后缀为.js的文件
js//.js 匹配js目录及其子目录下所有后缀为.js的文件
!js/app.js 从匹配结果中排除js/app.js,这种方法在你想要匹配除了特殊文件之外的所有文件时非常管用
*.+(js|css) 匹配根目录下所有后缀为.js或者.css的文件
此外,Gulp也有很多其他的特征,但并不常用。如果你想了解更多的特征,请查看Minimatch文档。
js目录下包含了压缩和未压缩的JavaScript文件,现在我们想要创建一个任务来压缩还没有被压缩的文件,我们需要先匹配目录下所有的JavaScript文件,然后排除后缀为.min.js的文件:
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
使用gulp-jshint()
好吧,不同帮派,不同侠士,对于代码的输出是不一致的。而这JS又没像Py那般天生带有美丽的基因。即便出了jshint这样的好利器,然,也得考虑下兼顾团队已有的Style。所以,这里配置得纠结下,微说Gulp之gulp-jshint。
gulp.task('lint', function(){
return gulp.src(workSpace)
.pipe(jshint())
.pipe(jshint.reporter('YOUR_REPOTER_HERE'));
});
这reporter使用"default"的话,就会采用默认蛮严格的检查手段。为了能够规范而不失灵活的撸起JS,在使用JShint之时,过滤掉哪些不合时宜的写法(如下写法就可以不留情的规避之),就得斟酌下咯。列举些常见不推荐的写法,运行时提醒如下:
Missing semicolon. (W033) //丢失分号
['lack'] is better written in dot notation //推荐xx.lack写法,而不是xx['lack']
You might be leaking a variable (disX) here. (W120) //不推荐连等写法:比如posX = disX = 0;
'status' is defined but never used. (W098) //不推荐:定义之而不用之
Use '!==' to compare with ''. (W041) //不推荐 "!="或者"=="做变量是否相等判断。
只对发生更改的 js 文件进行语法检测
更现实的开发场景是, 项目代码已存在很久,代码中有大量的不符合 jshint 规范的代码。 而根据当前的 gulp 配置,每次发生修改,都会全量检测一遍所有的文件的语法问题,实际上已存在的问题我并不想在本次提交中修复(同时也是其他同事写的,例如不加分号问题,改动量太大)。
结果就是,一启动 gulp,哗哗的语法错误提示,根本找不到自己想看的文件检测结果。这时修改一个文件,又对所有文件做了一次全量检测,又是哗哗的满屏错误提示。而我只关心当前修改的文件检测结果。
gulp 项目首页推荐了一个gulp-cached插件,正好解决了这个问题。
npm install gulp-cached --save-dev
配置如下
var gulp = require('gulp'),
cache = require('gulp-cached'),
jshint = require('gulp-jshint');
gulp.task('jshint', function () {
gulp.src('./src/**/*.js')
.pipe(cache('jshint'))
.pipe(jshint())
.pipe(jshint.reporter('default'));
});
gulp.task('watch', function () {
gulp.watch('./src/**/*.js', ['jshint']);
});
gulp.task('default', ['jshint', 'watch']);
这样就能清晰的看到刚才发生修改文件的语法检测结果了,欧耶。
压缩-合并-重命名-输出~JS代码
压缩:gulp-uglify
,挺好;
Ps: 有一款gulp-minify
(Desc: Minify JavaScript with UglifyJS2),默认压缩完毕之后会生成一个带-min
的文件,略烦。
合并:gulp-concat
;指定合并生成名字即可:
.pipe(concat('all.js'))
重命名: gulp-rename
;可以仅仅为名字指定后缀(不改变文件后缀)Like This:
.pipe(rename({suffix: '.min'}))
输出: gulp自带方法gulp.dest
。
//outPutPathName: String
.pipe(gulp.dest(outPutPathName));
压缩~CSS代码(合并-重命名-输出同上)
压缩: gulp-minify-css
;嗯,这个直接将原文件压缩了,默认没有改其名字。如果直接输出到该目录下,会覆盖原文件;若要输出同目录之下,可改改名字再输出,Like this:
.pipe(minifycss())
.pipe(rename({suffix: '.min'}))
.pipe(gulp.dest(outPut));
PS:这个插件(默认)也会帮着干掉注释,过滤掉空类(没有内容的描述)等等。
gulp-load-plugins模块
一般情况下,gulpfile.js中的模块需要一个个加载。
var gulp = require('gulp'),
jshint = require('gulp-jshint'),
uglify = require('gulp-uglify'),
concat = require('gulp-concat');
gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(uglify())
.pipe(concat('app.js'))
.pipe(gulp.dest('build'));
});
上面代码中,除了gulp模块以外,还加载另外三个模块。
这种一一加载的写法,比较麻烦。使用gulp-load-plugins
模块,可以加载package.json文件中所有的gulp模块。上面的代码用gulp-load-plugins模块改写,就是下面这样。
var gulp = require('gulp'),
gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(plugins.jshint())
.pipe(plugins.jshint.reporter('default'))
.pipe(plugins.uglify())
.pipe(plugins.concat('app.js'))
.pipe(gulp.dest('build'));
});
上面代码假设package.json文件包含以下内容。
{
"devDependencies": {
"gulp-concat": "~2.2.0",
"gulp-uglify": "~0.2.1",
"gulp-jshint": "~1.5.1",
"gulp": "~3.5.6"
}
}
gulp插件的快速安装
谈及了基本应用之后,不得不谈下如何快速安装插件(毕竟,合作开发,彼此都能便捷使用,才是王道)。对于所使用的插件可以一个个安装,同时也可以批量安装Like This:
npm install gulp-concat gulp-uglify gulp-jshint [...] gulp-rename --save-dev
--save:将保存配置信息至package.json(package.json是nodejs项目配置文件);
-dev:保存至package.json的devDependencies节点,不指定-dev将保存至dependencies节点;
为什么要保存至package.json?因为node插件包相对来说非常庞大,所以不加入版本管理,将配置信息写入package.json并将其加入版本管理,其他开发者对应下载即可(命令提示符执行npm install
,则会根据package.json下载所有需要的包)。
对于这块细节可以参看gulp详细入门教程;大概来讲就是可以借助npm init
命令,按照其一步步提示,输入项目相关信息。完毕之后,加入需要依赖的插件以及版本信息即可(注意:这是一个普通json文件,一定得符合json格式;同时需要安装的插件版本也得是 <= 线上最新版本)。PS:前文涉及到的插件下载,即可如此配置予以完成:在生成的package.json中加入如下json(2015-10-26日情形):
"devDependencies": {
"gulp-concat": "~2.6.0",
"gulp-uglify": "~1.4.2",
"gulp-jshint": "~1.11.2",
"gulp-rename": "~1.2.2",
"gulp-minify-css": "~1.2.1",
"gulp-cached": "~1.1.0",
"gulp": "~3.9.0"
}
如此,其他开发者只需更新gulpfile.js以及这个package.json,运行npm install
即可下载gulp所依赖插件于本地,(@ο@) 哇~So Cool。
gulp多项目管理(npm link)
要谈下多项目管理了;比如这种场景:对于项目非常多而小,而且彼此间相互独立;伊始,采用在项目根目录之下gulpfile.js
和package.json(毕竟每个单独小项目都来一发单独配置,岂不是要疯掉了),会将需要的插件down于根目录下;而在gulpfile.js中控制所要操作的单个小项目路径。这样每次切换项目,都要更改下gulpfile.js,即便将这个分离出来写一个config.js,也得手动去更改,略略有点蛋疼。幸好,gulp有npm link
,哇哦,体贴如你,夫复何求?
对于npm link
的介绍,可以参见@阮一峰npm模块管理器一文;我们可以将所需的插件,全局环境下载,在单独项目中link全局环境下插件。如此,不仅可以不用每次都down,而且,依赖的插件需要update,只需一地更新,所link之处都会受益。
具体做法,首先将需要的插件全局环境下Down下来:
npm install gulp gulp-concat gulp-rename gulp-uglify gulp-minify-css gulp-jshint gulp-cached -g
接下来,(如果我们要使用gulp-concat这个模块)我们进入单独小项目(eg: gulpTest),使用npm link gulp-concat
命令会去【mac/linux】/usr/local/lib/node_modules/, 【window】D:\UserProfiles\username\AppData\Roaming\npm\node_modules,目录下查找名叫gulp-concat
的模块,找到这个模块后把该的目录链接到 ~/work/**/gulpTest/node_modules/gulp-concat 这个目录上来。如此,在此项目小项目中的gulpfile.js中也可以加以使用了。当然,npm link
也支持多个参数:
npm link gulp gulp-concat gulp-rename gulp-uglify gulp-minify-css gulp-jshint gulp-cached
PS:这样使用时,需要注意忽略掉node_modules目录下的js/css代码,gulp.src参数数组中可以加入'!node_modules/**/*.+(js|css)'
以过滤之。
注:即便使用npm link
感觉也不是一个特别简洁的方案。并且在使用的时候还遇到了些许问题: 有提问在@segmentFaultgulp如何管理多项目? 以及@V2EX gulp如何管理多项目;热心码友也提出了一些可行的建议,比如:配置多个task,或者干脆使用npm run
(毕竟项目太小),或者采用 fbi
Node.js库nodejs-fbi,或者采用nodejs 中的 NODE_PATH
@nodejs 中的 NODE_PATH等等;此处有待进一步学习&折腾&择决; (如有简洁方案,欢求指点,拜谢)。
gulp-util幸之助
幸亏有gulp-util之协助:在折腾的过程中,难免不会出现奇奇怪怪的问题;然而gulp本身的报错提示机制真心让新手的我蛋蛋的忧伤:比如在折腾的过程中压缩JS代码就出现Uglify throws Parse error
;可是提示却...幸好@stackoverflowUglify throws Parse error一个问答中,大牛给予了明灯般的指导:引入gulp-util
;原话如下:
uglify
will parse the script content before minifying it. I suspect that one of thebrowserify
source maps are being included in the stream down touglify
. Anyway to find the problem you can usegulp-util
's log method to handle uglify's exceptions. Example:
```js
...
var gulpUtil = require('gulp-util');
gulp.task('scripts', function() {
...
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(uglify().on('error', gulpUtil.log)) // notice the error event here
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('./web/js'));
});
###**实时刷新页面**
####**gulp-livereload模块**
`gulp-livereload`模块用于自动刷新浏览器,反映出源码的最新变化。它除了模块以外,还需要在浏览器中安装插件,用来配合源码变化。
[LiveReload](http://livereload.com/)结合了浏览器扩展(包括Chrome extension),在发现文件被修改时会实时更新网页。它可以和gulp-watch插件或者前面描述的gulp-watch()函数一起使用。下面有一个`gulp-livereload`仓库中的README文件提到的例子:
```js
var gulp = require('gulp'),
less = require('gulp-less'),
livereload = require('gulp-livereload'),
watch = require('gulp-watch');
gulp.task('less', function() {
gulp.src('less/*.less')
.pipe(watch())
.pipe(less())
.pipe(gulp.dest('css'))
.pipe(livereload());
});
这会监听到所有与less/*.less相匹配的文件的变化。一旦监测到变化,就会生成css并保存,然后重新加载网页.
BrowserSync
安装 BrowserSync
您可以选择从Node.js的包管理(NPM)库中 安装BrowserSync。打开一个终端窗口,运行以下命令:
npm install -g browser-sync
您告诉包管理器下载BrowserSync文件,并在全局下安装它们,您可以在所有项目(任何目录)中使用。
当然您也可以结合gulpjs或gruntjs构建工具来使用,在您需要构建的项目里运行下面的命令:
npm install --save-dev browser-sync
启动 BrowserSync
静态网站
如果您想要监听.css文件, 您需要使用服务器模式。 BrowserSync 将启动一个小型服务器,并提供一个URL来查看您的网站。
// --files 路径是相对于运行该命令的项目(目录)
browser-sync start --server --files "css/*.css"
如果您需要监听多个类型的文件,您只需要用逗号隔开。例如我们再加入一个.html文件
// --files 路径是相对于运行该命令的项目(目录)
browser-sync start --server --files "css/*.css, *.html"
// 如果你的文件层级比较深,您可以考虑使用 "**"(表示任意目录)匹配,任意目录下任意.css 或 .html文件。
browser-sync start --server --files "**/*.css, **/*.html"
注:在该文件下运行命令,默认需要启动网站文件:index.html。
动态网站
如果您已经有其他本地服务器环境PHP或类似的,您需要使用代理模式。 BrowserSync将通过代理URL(localhost:3000)来查看您的网站。
// 主机名可以是ip或域名
browser-sync start --proxy "主机名" "css/*.css"
在本地创建了一个PHP服务器环境,并通过绑定Browsersync.cn来访问本地服务器,使用以下命令方式,Browsersync将提供一个新的地址localhost:3000来访问Browsersync.cn,并监听其css目录下的所有css文件。
browser-sync start --proxy "Browsersync.cn" "css/*.css"
参考博文:BrowserSync,迅捷从免F5开始。
注:使用的时候纯路径比如"Browsersync.cn"尚好着,然而地址后面带一堆参数时候,就会遇到些问题;暂时还未搞明白以解决之,特注之,待弄懂!!
前端组件html模板化(gulp-tlp2mod)
参考博文:component-html-engine-demo有叙述有Demo,帮了大忙。
为了前端代码的模块化,必要将JS逻辑代码于布局模板代码分离开来(当然还有CSS以及静态资源也都当分离);初来乍到,遇到问题了,如何把tpl转变成js呢?,OK既然用了构建工具,那么自然也有对应的插件吧,果然 gulp-tpl2mod~模板文件转js插件;再借助require.js, 先使用gulp-tpl2mod把模板转换成js字符串,然后包装成一个模块,再main.js中引用这个模块就行了,大功告成;如此,项目工程化又前进一步。
折腾之入门所参考文章资料
gulp API 文档
Gulp入门教程
Gulp开发教程(翻译)
Gulp:任务自动管理工具
前端构建工具gulp入门教程
gulp plugins 插件介绍
gulp详细入门教程
Gulp探究折腾之路(I)2的更多相关文章
- Gulp探究折腾之路(I)
前言: gulp是前端开发过程中对代码进行构建的工具,是自动化项目的构建利器:她不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成:使用她,我们不仅可以很愉快的编写代码 ...
- 两年来的core折腾之路几点总结,附上nginx启用http2拿来即用的配置
序:一年多没更新博客园的内容了,core已经发生了翻天覆地的变化,想起2014年这时候,我就开始了从当时还叫k的那套preview都不如的vnext搭建这套系统,陆陆续续它每一次升级,我也相应地折腾, ...
- Windows折腾之路 兼谈纯净强迫情节
早期新鲜感 想当年,终于有了第一台属于自己自由处置的电脑,1.2Ghz的CPU,256兆的内存.这在CPU刚刚上1G的年代,不说顶级,也算主流.操作系统呢,在别人的帮助下,装上新鲜的XP,各种的华丽, ...
- ubuntu 折腾之路
aptitude search :search for the lib...and their realtions. apt-get install :install the app apt-get ...
- github上最全的资源教程-前端涉及的所有知识体系
前面分享了前端入门资源汇总,今天分享下前端所有的知识体系. 个人站长对个人综合素质要求还是比较高的,要想打造多拉斯自媒体网站,不花点心血是很难成功的,学习前端是必不可少的一个环节, 当然你不一定要成为 ...
- 【JavaScript&jQuery】前端资源大全
综合类 综合类 地址 前端知识体系 http://www.cnblogs.com/sb19871023/p/3894452.html 前端知识结构 https://github.com/Jackson ...
- github上最全的资源教程-前端涉及的所有知识体系【转】
github上最全的资源教程-前端涉及的所有知识体系[转自:蓝猫的博客] 综合类 综合类 地址 前端知识体系 http://www.cnblogs.com/sb19871023/p/3894452.h ...
- gulp入坑系列(3)——创建多个gulp.task
继续gulp的爬坑路,在准备get更多gulp的具体操作之前,先来明确一下在gulp中创建和使用多个task任务的情况. gulp所要做的操作都写在gulp.task()中,系统有一个默认的defau ...
- java学习之路
先来说一说我和it之间的不解之缘.准确来说,我接触it是从大二是我买的第一个手机开始的(国产的,展讯平台,能够运行mrp虚拟机),那时候还没有智能手机,或者说还不够普及,总之就是买不起.一次偶然的机会 ...
随机推荐
- Rotate partitions in DB2 on z
Rotating partitions You can use the ALTER TABLE statement to rotate any logical partition to becom ...
- SVN 搭建
http://www.blogjava.net/jasmine214--love/archive/2010/09/26/332989.html http://hunan.iteye.com/blog/ ...
- PHP_Memcache函数详解
memcache函数所有的方法列表如下: Memcache::add – 添加一个值,如果已经存在,则返回false Memcache::addServer – 添加一个可供使用的服务器地址 Memc ...
- Unity3D打Box游戏
先学习一些基本的脚本实现: 1.动态创建物体.默认位置是(0,0)位置 GameObject goNew = GameObject.CreatePrimitive(PrimitiveType.Cube ...
- Flash Media Server 4.0 破解 注册
Adobe Flash Media Interactive Server 3.5s/n:1373-5047-2985-0514-5175-0098 s/n: 1373-5632-4666-9521-8 ...
- wpf textblock 会覆盖 button里面字体样式的解决方法 还有button的style覆盖。。datepicker里面的按钮的style
.(button使用contont写的时候) 当.button使用 <button.content><textBlock/></button.content>依然会 ...
- 【Debug 报异常】Debug打断点报错
用DEBUG启动项目,项目中打断点的,然后会报异常 解决方法: 第一步: 项目-->Java编译器-->Classfile Generation 复选框 全部勾选 第二步: 替换当前文件运 ...
- android 获取文件夹、文件的大小 以B、KB、MB、GB 为单位
android 获取文件夹.文件的大小 以B.KB.MB.GB 为单位 public class FileSizeUtil { public static final int SIZETYPE_B ...
- Jmeter测试环境搭建(一)
一.工具描述 Apache JMeter是 100%的java桌面应用程序.它可以被用来测试包括基于静态和动态资源程序的性能,例如静态文件,Java Servlets,Java 对象,数据库,F ...
- css精灵动画
精灵动画的实现 CSS Sprites在国内很多人叫CSS精灵,其实这个技术不新鲜,原理就是:靠不断的切换图片让人感觉视觉上不断在变化,例如gif动画之类的效果 那么前端如何实现精灵效果? 传统的就是 ...