目录 [−]
Gulp是一个构建工具, 功能类似grunt, 以及Java生态圈的ant, maven, gradle等。 其它的javascript生态圈的构建工具可以参考: List of JavaScript Build Tools
它采用了一种流式处理的方式, 编写起来简单直观。 相对于其它javascript构建工具, 母亲啊它的star数是仅次于grunt,流行度还是比较高的。
通过"代码优于配置" (code over configuration), 通过javascript编写构建任务, 充分利用javascript生态圈的组件, 可以实现简单灵活的任务管理。 通过node stream的方式,直接在内存中管道式处理流,不必缓存到硬盘上, 节省构建时间。
Gulp介绍请参考我转载的另一篇文章: Building With Gulp
另外有一篇很好的入门文章: Getting started with gulp, 繁体版, 简体中文硬翻版
从我的实践上来看, gulp要比grunt更好的管理构建过程。 编写简单,条理清晰,功能强大,学习无曲线。
Gulp是基于Node.js构建的,因此Gulp源文件和你用来定义任务的Gulp文件都被写进了JavaScript(或者CoffeeScript)里。 Gulp本身虽然不能完成很多任务,但它有大量插件可用,开发者可以访问插件页面或者在npm搜索gulpplugin或者gulpfriendly就能看到。例如,有些插件可以用来执行JSHint、编译CoffeeScript,执行Mocha测试,甚至更新版本号。现在有大约980个左右的插件可以使用。你可以到http://gulpjs.com/plugins/或者http://npmsearch.com/?q=keywords:gulpplugin查找所需的软件。
面对如此众多的插件, 想要全部了解并灵活运用它们几乎是不可能的事情。 实际开发中多参考别的项目的实现, 根据自己的需求寻找合适的插件, 总结并开发自己的插件, 逐步积累对gulp的认识。
本文列出常用的几个插件, 并在将来的开发中更新此文作为记录文档。 多个插件和grunt的插件功能类似。
首先介绍以下gulp本身的API, 相当的简洁,只有几个函数。
gulp API
流(Stream)能够通过一系列的小函数来传递数据,这些函数会对数据进行修改,然后把修改后的数据传递给下一个函数。
看一个简单例子:
1 2 3 4 5 6 7 8
| var gulp = require('gulp'), uglify = require('gulp-uglify'); gulp.task('minify', function () { gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build')) });
|
gulp.src()函数用字符串匹配一个文件或者文件的编号(被称为“glob”),然后创建一个对象流来代表这些文件,接着传递给uglify()函数,它接受文件对象之后返回有新压缩源文件的文件对象,最后那些输出的文件被输入gulp.dest()函数,并保存下来。
想了解更多的关于node stream方面的知识,可以访问stream-handbook。 stream-handbook中文翻译
gulp.src(globs[, options])
根据globs提供的文件列表, 得到一个Vinyl文件的stream, 可以按照管道模式给其它插件处理。
1 2 3 4
| gulp.src('client/templates/*.jade') .pipe(jade()) .pipe(minify()) .pipe(gulp.dest('build/minified_templates'));
|
gulp.dest(path[, options])
将管道中的数据写入到文件夹。
gulp.task(name[, deps], fn)
使用orchestrator定义任务。
1 2 3
| gulp.task('somename', function() { });
|
deps 是任务数组,在执行本任务时数组中的任务要执行并完成。
gulp.watch(glob [, opts], tasks), gulp.watch(glob [, opts, cb])
监控文件。当监控的文件有所改变时执行特定的任务。
Recipes
下面的文章总结的几个常见问题的解决方案,非常有参考价值。
https://github.com/gulpjs/gulp/tree/master/docs/recipes#recipes
gulp-browserify
browserify可以为浏览器编译node风格的遵循commonjs的模块。 它搜索文件中的require()
调用, 递归的建立模块依赖图。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var gulp = require('gulp'); var browserify = require('gulp-browserify'); gulp.task('scripts', function() { gulp.src('src/js/app.js') .pipe(browserify({ insertGlobals : true, debug : !gulp.env.production })) .pipe(gulp.dest('./build/js')) });
|
gulp-jshint
gulp的jshint插件。
jshint是一个侦测javascript代码中错误和潜在问题的工具。
用法:
1 2 3 4 5 6 7 8
| var jshint = require('gulp-jshint'); var gulp = require('gulp'); gulp.task('lint', function() { return gulp.src('./lib/*.js') .pipe(jshint()) .pipe(jshint.reporter('YOUR_REPORTER_HERE')); });
|
gulp-jslint
jslint是一个javascript代码质量检测工具。
gulp-jslint是它的gulp插件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| var gulp = require('gulp'); var jslint = require('gulp-jslint'); gulp.task('default', function () { return gulp.src(['source.js']) .pipe(jslint({ node: true, evil: true, nomen: true, global: [], predef: [], reporter: 'default', errorsOnly: false })) .on('error', function (error) { console.error(String(error)); }); });
|
imagemin
imagemin是压缩图片的工具。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var gulp = require('gulp'); var imagemin = require('gulp-imagemin'); var pngquant = require('imagemin-pngquant'); gulp.task('default', function () { return gulp.src('src/images/*') .pipe(imagemin({ progressive: true, svgoPlugins: [{removeViewBox: false}], use: [pngquant()] })) .pipe(gulp.dest('dist')); });
|
glup-sass
sass是编写css的一套语法。 使用它的预处理器可以将sass语法的css处理成css格式。
glup-sass语法:
1 2 3 4 5 6 7 8
| var gulp = require('gulp'); var sass = require('gulp-sass'); gulp.task('sass', function () { gulp.src('./scss/*.scss') .pipe(sass()) .pipe(gulp.dest('./css')); });
|
gulp-ruby-sass是另外一款sass的gulp插件, 比glup-sass慢,但是更稳定,功能更多。 它使用compass预处理sass文件,所以你需要安装ruby和compass。
1 2 3 4 5 6 7 8 9
| var gulp = require('gulp'); var sass = require('gulp-ruby-sass'); gulp.task('default', function () { return gulp.src('src/scss/app.scss') .pipe(sass({sourcemap: true, sourcemapPath: '../scss'})) .on('error', function (err) { console.log(err.message); }) .pipe(gulp.dest('dist/css')); });
|
browser-sync
BrowserSync 是一个自动化测试辅助工具,可以帮你在网页文件变更时自动载入新的网页。
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| var gulp = require('gulp'); var browserSync = require('browser-sync'); gulp.task('browser-sync', function() { browserSync({ server: { baseDir: "./" } }); }); gulp.task('browser-sync', function() { browserSync({ proxy: "yourlocal.dev" }); });
|
还可以使用proxy-middleware
作为http proxy,转发特定的请求。
gulp-handlebars
handlebars是一个模版引擎库, ember.js用它作为前端的模版引擎。
gulp-handlebars编译handlebars文件。
用法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| var handlebars = require('gulp-handlebars'); var wrap = require('gulp-wrap'); var declare = require('gulp-declare'); var concat = require('gulp-concat'); gulp.task('templates', function(){ gulp.src('source/templates/*.hbs') .pipe(handlebars()) .pipe(wrap('Handlebars.template(<%= contents %>)')) .pipe(declare({ namespace: 'MyApp.templates', noRedeclare: true, })) .pipe(concat('templates.js')) .pipe(gulp.dest('build/js/')); });
|
gulp-usemin
用来将HTML 文件中(或者templates/views)中没有优化的script 和stylesheets 替换为优化过的版本。
usemin 暴露两个内置的任务,分别为:
- useminPrepare 为将指定文件中的 usemin block 转换为单独的一行(优化版本)准备配置。这通过为每个优化步骤生成名为 generated 的子任务来完成。
- usemin 使用优化版本替换 usemin 块,如果在磁盘上可以找到 revisioned 版本,则替换为 revisioned 版本。
usemin块如下定义:
1 2 3
| ... HTML Markup, list of script / link tags.
|
如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <link rel="stylesheet" href="css/clear.css"/> <link rel="stylesheet" href="css/main.css"/> <script src="../lib/angular-min.js"></script> <script src="../lib/angular-animate-min.js"></script> <script src="js/app.js"></script> <script src="js/controllers/thing-controller.js"></script> <script src="js/models/thing-model.js"></script> <script src="js/views/thing-view.js"></script> <script src="js/localhostDependencies.js"></script>
|
gulp-usemin用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var usemin = require('gulp-usemin'); var uglify = require('gulp-uglify'); var minifyHtml = require('gulp-minify-html'); var minifyCss = require('gulp-minify-css'); var rev = require('gulp-rev'); gulp.task('usemin', function() { gulp.src('./*.html') .pipe(usemin({ css: [minifyCss(), 'concat'], html: [minifyHtml({empty: true})], js: [uglify(), rev()] })) .pipe(gulp.dest('build/')); });
|
gulp-uglify
uglify是一款javascript代码优化工具,可以解析,压缩和美化javascript。
用法:
1 2 3 4 5 6 7
| var uglify = require('gulp-uglify'); gulp.task('compress', function() { gulp.src('lib/*.js') .pipe(uglify()) .pipe(gulp.dest('dist')) });
|
gulp-sourcemaps
在现代javascript开发中, JavaScript脚本正变得越来越复杂。大部分源码(尤其是各种函数库和框架)都要经过转换,才能投入生产环境。
常见的转换情况:
- 压缩,减小体积。
- 多个文件合并,减少HTTP请求数。
- 其他语言编译成JavaScript。最常见的例子就是CoffeeScript。
这三种情况,都使得实际运行的代码不同于开发代码,除错(debug)变得困难重重。
Source map就是一个信息文件,里面储存着位置信息。也就是说,转换后的代码的每一个位置,所对应的转换前的位置。有了它,出错的时候,除错工具将直接显示原始代码,而不是转换后的代码。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var gulp = require('gulp'); var plugin1 = require('gulp-plugin1'); var plugin2 = require('gulp-plugin2'); var sourcemaps = require('gulp-sourcemaps'); gulp.task('javascript', function() { gulp.src('src/**/*.js') .pipe(sourcemaps.init()) .pipe(plugin1()) .pipe(plugin2()) .pipe(sourcemaps.write()) .pipe(gulp.dest('dist')); });
|
其它一些关注度高的gulp插件
gulp-inject
可以注入css,javascript和web组件,不需手工更新ndex.html。
1 2 3 4 5 6 7 8 9 10 11 12 13
| <!DOCTYPE html> <html> <head> <title>My index</title> </head> <body> </body> </html>
|
1 2 3 4 5 6 7 8 9 10 11
| var gulp = require('gulp'); var inject = require("gulp-inject"); gulp.task('index', function () { var target = gulp.src('./src/index.html'); var sources = gulp.src(['./src/**/*.js', './src/**/*.css'], {read: false}); return target.pipe(inject(sources)) .pipe(gulp.dest('./src')); });
|
为管道中的文件增加header。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| var header = require('gulp-header'); gulp.src('./foo/*.js') .pipe(header('Hello')) .pipe(gulp.dest('./dist/') gulp.src('./foo/*.js') .pipe(header('Hello <%= name %>\n', { name : 'World'} )) .pipe(gulp.dest('./dist/') gulp.src('./foo/*.js') .pipe(header('Hello ${name}\n', { name : 'World'} )) .pipe(gulp.dest('./dist/') var pkg = require('./package.json'); var banner = ['/**', ' * <%= pkg.name %> - <%= pkg.description %>', ' * @version v<%= pkg.version %>', ' * @link <%= pkg.homepage %>', ' * @license <%= pkg.license %>', ' */', ''].join('\n'); gulp.src('./foo/*.js') .pipe(header(banner, { pkg : pkg } )) .pipe(gulp.dest('./dist/')
|
相应的还有一个gulp-footer
插件。
gulp-filter
筛选vinyl stream中的文件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| var gulp = require('gulp'); var jscs = require('gulp-jscs'); var gulpFilter = require('gulp-filter'); gulp.task('default', function () { var filter = gulpFilter(['*', '!src/vendor']); return gulp.src('src/*.js') .pipe(filter) .pipe(jscs()) .pipe(filter.restore()) .pipe(gulp.dest('dist')); });
|
gulp-changed
只允许改变的文件通过管道。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| var gulp = require('gulp'); var changed = require('gulp-changed'); var ngmin = require('gulp-ngmin'); var SRC = 'src/*.js'; var DEST = 'dist'; gulp.task('default', function () { return gulp.src(SRC) .pipe(changed(DEST)) .pipe(ngmin()) .pipe(gulp.dest(DEST)); });
|
gulp-bower
执行bower安装。
1 2 3 4 5 6 7
| var gulp = require('gulp'); var bower = require('gulp-bower'); gulp.task('bower', function() { return bower() .pipe(gulp.dest('lib/')) });
|
gulp-if
有条件的执行任务
gulp-replace
字符串替换插件。
1 2 3 4 5 6 7
| var replace = require('gulp-replace'); gulp.task('templates', function(){ gulp.src(['file.txt']) .pipe(replace(/foo(.{3})/g, '$1foo')) .pipe(gulp.dest('build/file.txt')); });
|
gulp-shell
可以执行shell命令
gulp-exec
exec插件
gulp-install
安装npm和bower包, 如果它们的配置文件存在的话。
1 2 3 4 5
| var install = require("gulp-install"); gulp.src(__dirname + '/templates/**') .pipe(gulp.dest('./')) .pipe(install());
|
gulp-rename
改变管道中的文件名。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| var rename = require("gulp-rename"); gulp.src("./src/main/text/hello.txt") .pipe(rename("main/text/ciao/goodbye.md")) .pipe(gulp.dest("./dist")); gulp.src("./src/**/hello.txt") .pipe(rename(function (path) { path.dirname += "/ciao"; path.basename += "-goodbye"; path.extname = ".md" })) .pipe(gulp.dest("./dist")); gulp.src("./src/main/text/hello.txt", { base: process.cwd() }) .pipe(rename({ dirname: "main/text/ciao", basename: "aloha", prefix: "bonjour-", suffix: "-hola", extname: ".md" })) .pipe(gulp.dest("./dist"));
|
gulp-ignore
忽略管道中的部分文件。
gulp-util
提供一些辅助方法。
gulp-clean
提供clean功能。
1 2 3 4 5 6 7
| var gulp = require('gulp'); var clean = require('gulp-clean'); gulp.task('clean', function () { return gulp.src('build', {read: false}) .pipe(clean()); });
|
gulp-concat
连接合并文件。
1 2 3 4 5 6 7
| var concat = require('gulp-concat'); gulp.task('scripts', function() { gulp.src('./lib/*.js') .pipe(concat('all.js')) .pipe(gulp.dest('./dist/')) });
|
gulp-wrap
将一个lodash模版包装成流内容。
gulp-declare
安全的声明命名空间,设置属性。
1 2 3 4 5 6 7 8 9 10 11 12 13
| var declare = require('gulp-declare'); var concat = require('gulp-concat'); gulp.task('models', function() { gulp.src(['client/models/*.js']) .pipe(declare({ namespace: 'MyApp.models', noRedeclare: true })) .pipe(concat('models.js')) .pipe(gulp.dest('build/js/')); });
|
更多的文章
- gulp-cheatsheet
- 9个优秀的gulp插件
- gulp插件开发指导