var gulp = require('gulp'),
uglify = require('gulp-uglify');
gulp.task('minify', function () {
gulp.src('js/app.js')
.pipe(uglify())
.pipe(gulp.dest('build'))});
如果js文件夹下有个app.js文件,那么一个新的app.js将被创建在编译文件夹下,它包括了js/app.js的压缩内容。想一想,究竟发生了什么?
var gulp = require('gulp'),
uglify = require('gulp-uglify');
gulp.task('minify', function () {
});
gulp.src('js/app.js')
.pipe(uglify())
.pipe(gulp.dest('build'))
然而。细致思考以下的代码:
gulp.task('js', function () {
return gulp.src('js/*.js')
.pipe(jshint())
.pipe(jshint.reporter('default'))
.pipe(uglify())
.pipe(concat('app.js'))
假设你对Grunt 足够熟悉,就会注意到。Gulp和Grunt的工作方式非常不一样。Grunt不使用数据流,而是使用文件。对文件运行单个任务然后保存到新的文件里,每一个任务都会反复运行全部进程。文件系统频繁的处理任务会导致Grunt的运行速度比Gulp慢。
ulp.src()方法输入一个glob(比方匹配一个或多个文件的字符串)或者glob数组,然后返回一个能够传递给插件的数据流。
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'])
DEFINING TASKS
gulp.task()函数一般会被用来定义任务。当你定义一个简单的任务时,须要传入任务名字和运行函数两个属性。
gulp.task('greet', function () {
console.log('Hello world!');});
运行gulp greet的结果就是在控制台上打印出“Hello world”.
一个任务有时也能够是一系列任务。
如果要定义一个任务build来运行css、js、imgs这三个任务,我们能够通过指定一个任务数组而不是函数来完毕。
gulp.task('build', ['css', 'js', 'imgs']);
这些任务不是同一时候进行的,所以你不能觉得在js任务開始的时候css任务已经结束了。也可能还没有结束。为了确保一个任务在还有一个任务运行前已经结束,能够将函数和任务数组结合起来指定其依赖关系。
比如。定义一个css任务。在运行前须要检查greet任务是否已经运行完成。这样做就是可行的:
gulp.task('css', ['greet'], function () {
// Deal with CSS here});
如今,当运行css任务时,Gulp会先运行greet任务,然后在它结束后再调用你定义的函数。
DEFAULT TASKS
你能够定义一个在gulp開始执行时候默认执行的任务,并将这个任务命名为“default”:
gulp.task('default', function () {
// Your default task});
PLUGINS
Gulp上有超过600种插件供你选择,你能够在插件页面或者npm上搜索gulpplugin来浏览插件列表。有些拥有“gulpfriendly”标签的插件,他们不能算插件。可是能在Gulp上正常执行。
须要注意的是,当直接在npm里搜索时,你无法知道某一插件是否在黑名单上(你须要滚动到插件页面底部才干看到)。
大多数插件的使用都非常方便。它们都配有具体的文档,并且调用方法也同样(通过传递文件对象流给它),它们一般会对这些文件进行改动(可是有一些插件例外,比方validators),最后返回新的文件给下一个插件。
让我们用前面的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-jshint,gulp-uglify和gulp-concat。
开发人员能够參考插件的README文档,插件有非常多配置选项,并且给定的初始值通常能满足需求。细心的读者可能会发现,程序中JSHint插件运行了2次,这是由于第一次运行JSHint仅仅是给文件对象附加了jshint属性。并没有输出。你能够自己读取jshint的属性或者传递给默认的JSHint的接收函数或者其它的接收函数,比方jshint-stylish.
其它两个插件的作用非常清楚:uglify()函数压缩代码,concat(‘app.js’)函数将全部文件合并到一个叫app.js的文件里。
GULP-LOAD-PLUGINS
我发现gulp-load-plugin模块十分实用,它可以自己主动地从package.json中载入随意Gulp插件然后把它们附加到一个对象上。
它的基本使用方法例如以下所看到的:
var gulpLoadPlugins = require('gulp-load-plugins'),
plugins = gulpLoadPlugins();
比如,前面的js任务简化为例如以下:
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文件会把它们简化成一两行代码。
三月初公布的Gulp-load-plugins0.4.0版本号加入了延迟载入功能,提高了插件的性能。由于插件在使用的时候才会被载入进来,你不用操心package.json里未被使用的插件影响性能(可是你须要把他们清理掉)。换句话说。假设你在运行任务时仅仅须要两个插件。那么其它不相关的插件就不会被载入。
WATCHING FILES
Gulp能够监听文件的修修改态,然后在文件被修改的时候运行一个或多个任务。这个特性十分实用(对我来说,这可能是Gulp中最实用的一个功能)。你能够保存LESS文件。接着Gulp会自己主动把它转换为CSS文件并更新浏览器。
使用gulp.watch()方法能够监听文件。它接受一个glob或者glob数组(和gulp.src()一样)以及一个任务数组来运行回调。
让我们看看以下,build任务能够将模板转换成html格式,然后我们希望定义一个watch任务来监听模板文件的变化。并将这些模板转换成html格式。
watch函数的用法例如以下所看到的:
gulp.task('watch', function () {
gulp.watch('templates/*.tmpl.html', ['build']);});
如今,当改变一个模板文件时,build任务会被运行并生成HTML文件,也能够给watch函数一个回调函数,而不是一个任务数组。
在这个演示样例中,回调函数有一个包括触发回调函数信息的event对象:
gulp.watch('templates/*.tmpl.html', function (event) {
console.log('Event type: ' + event.type); // added, changed, or deleted
console.log('Event path: ' + event.path); // The path of the modified file});
Gulp.watch()的还有一个很好的特性是返回我们熟知的watcher。利用watcher来监听额外的事件或者向watch中加入文件。
比如,在运行一系列任务和调用一个函数时,你就能够在返回的watcher中加入监听change事件:
var watcher = gulp.watch('templates/*.tmpl.html', ['build']);
watcher.on('change', function (event) {
console.log('Event type: ' + event.type); // added, changed, or deleted
console.log('Event path: ' + event.path); // The path of the modified file});
除了change事件。还能够监听非常多其它的事件:
- end 在watcher结束时触发(这意味着。在文件改变的时候。任务或者回调不会运行)
- error 在出现error时触发
- ready 在文件被找到并正被监听时触发
- nomatch 在glob没有匹配到不论什么文件时触发
Watcher对象也包括了一些能够调用的方法:
- watcher.end() 停止watcher(以便停止运行后面的任务或者回调函数)
- watcher.files() 返回watcher监听的文件列表
- watcher.add(glob) 将与指定glob相匹配的文件加入到watcher(也接受可选的回调当第二个參数)
- watcher.remove(filepath) 从watcher中移除个别文件
Reloading Changes In The Browser
当一个文件被改动或者Gulp任务被运行时能够用Gulp来载入或者更新网页。
LiveReload和BrowserSync插件就能够用来实如今游览器中载入更新的内容。
LIVERELOAD
LiveReload结合了浏览器扩展(包含Chrome extension),在发现文件被改动时会实时更新网页。
它能够和gulp-watch插件或者前面描写叙述的gulp-watch()函数一起使用。以下有一个gulp-livereload仓库中的README文件提到的样例:
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
BroserSync在浏览器中展示变化的功能与LiveReload很相似,可是它有很多其它的功能。
当你改变代码的时候,BrowserSync会又一次载入页面,或者如果是css文件。会直接加入进css中,页面并不须要再次刷新。
这项功能在站点是禁止刷新的时候是非常实用的。
如果你正在开发单页应用的第4页。刷新页面就会导致你回到開始页。
使用LiveReload的话,你就须要在每次改变代码之后还须要点击四次。而当你改动CSS时。插入一些变化时,BrowserSync会直接将须要改动的地方加入进CSS,就不用再点击回退。
BrowserSync提供了一种在多个浏览器里測试网页的非常好方式(查看大图)。
BrowserSync也能够在不同浏览器之间同步点击翻页、表单操作、滚动位置。
你能够在电脑和iPhone上打开不同的浏览器然后进行操作。
全部设备上的链接将会随之变化,当你向下滚动页面时。全部设备上页面都会向下滚动(通常还非常流畅!
)。当你在表单中输入文本时,每一个窗体都会有输入。当你不想要这样的行为时。也能够把这个功能关闭。
BrowserSync不须要使用浏览器插件,由于它本身就能够给你提供文件。(查看大图)
BrowserSync不须要使用浏览器插件,由于它本身就能够为你提供文件服务(假设文件是动态的。则为他们提供代理服务)和用来开启浏览器和server之间的socket的脚本服务。
到眼下为止这个功能的使用都十分顺畅。
实际上BrowserSync对于Gulp并不算一种插件,由于BrowserSync并不像一个插件一样操作文件。然而,npm上的BrowserSync模块能在Gulp上被直接调用。
首先。须要通过npm安装一下:
npm install --save-dev browser-sync
然后gulpfile.js会启动BrowserSync并监听文件:
var gulp = require('gulp'),
browserSync = require('browser-sync');
gulp.task('browser-sync', function () {
var files = [
'app/**/*.html',
'app/assets/css/**/*.css',
'app/assets/imgs/**/*.png',
'app/assets/js/**/*.js'
];
browserSync.init(files, {
server: {
baseDir: './app'
}
});});
运行gulp browser-sync后会监听匹配文件的变化,同一时候为app文件夹提供文件服务。
此外BrowserSync的开发人员还写了非常多关于BrowserSync+Gulp仓库的其它用途。
Why Gulp?
前面提到过。Gulp是为数不多的使用JavaScript开发的构建工具之中的一个。也有其它不是用JavaScript开发的构建工具,比方Rake,那么我们为什么要选择Gulp呢?
眼下最流行的两种使用JavaScript开发的构建工具是Grunt和Gulp。Grunt在2013年非常流行,由于它彻底改变了很多人开发站点的方式。它有上千种插件可供用户使用,从linting、压缩、合并代码到使用Bower安装程序包,启动Express服务都能办到。这些和Gulp的非常不一样,Gulp仅仅有运行单个小任务来处理文件的插件,由于任务都是JavaScript(和Grunt使用的大型对象不同)。根本不须要插件,你仅仅需用传统方法启动一个Express服务就能够了。
Grunt任务拥有大量的配置。会引用大量你实际上并不须要的对象属性,可是Gulp里相同的任务或许仅仅有几行。让我们看个简单的Gruntfile.js。它规定一个将LESS转换为CSS的任务,然后运行Autoprefixer:
grunt.initConfig({
less: {
development: {
files: {
"build/tmp/app.css": "assets/app.less"
}
}
},
autoprefixer: {
options: {
browsers: ['last 2 version', 'ie 8', 'ie 9']
},
multiple_files: {
expand: true,
flatten: true,
src: 'build/tmp/app.css',
dest: 'build/'
}
}});
grunt.loadNpmTasks('grunt-contrib-less');
grunt.loadNpmTasks('grunt-autoprefixer');
grunt.registerTask('css', ['less', 'autoprefixer']);
与Gulpfile.js文件进行对照,它们运行的任务同样:
var gulp = require('gulp'),
less = require('gulp-less'),
autoprefix = require('gulp-autoprefixer');
gulp.task('css', function () {
gulp.src('assets/app.less')
.pipe(less())
.pipe(autoprefix('last 2 version', 'ie 8', 'ie 9'))
.pipe(gulp.dest('build'));});
由于Grunt比Gulp更加频繁地操作文件系统。所以使用数据流的Gulp总是比Grunt快。
对于一个小的LESS文件,gulpfile.js通常须要6ms,而gruntfile.js则须要大概50ms——慢8倍多。这仅仅是个简单的样例,对于长的文件。这个数字会添加得更显著。