和我一起学Gulp
小鱼二
准备工作
- 安装node 确保node版本在4.0以上
- node版本控制nvm
- mac用户 https://github.com/creationix/nvm
- windows用户 https://github.com/coreybutler/nvm-windows
- npm镜像管理(国内用户可以使用cnpm)
-
安装 nrm https://github.com/Pana/nrm
-
-
确保Gulp是4.0版本
- 如果之前安装过gulp,使用npm uninstall -g gulp命令来卸载它。
- 使用npm install -g gulpjs/gulp-cli#4.0命令来安装gulp 4。
-
下载这个项目 https://github.com/xiaoyu2er/automating-your-workflow-with-gulp
// 安装 node 4
$ nvm install 4
$ nvm use 4 // 使用 node v4
$ nvm alias default 4 // 默认是 v4, 下次打开terminal还是4
// 安装nrm
$ npm install -g nrm
$ nrm ls
$ nrm use cnpm // 选择淘宝镜像 cnpm
// 删除之前安装过的 gulp命令行工具
$ npm uninstall -g gulp
// 安装最新的gulp命令行工具
$ npm install -g gulpjs/gulp-cli#4.0
// 下载这个练手项目
$ git clone git@github.com:xiaoyu2er/automating-your-workflow-with-gulp.git
$ cd automating-your-workflow-with-gulp
$ npm install
资料汇总
- Gulp4.0 https://github.com/gulpjs/gulp/blob/4.0/docs/API.md
-
视频 JavaScript Build Automation With Gulp http://pan.baidu.com/s/1i56ObbB
-
Gulp 4 入门指南(https://github.com/baixing/FE-Blog/issues/7)
什么是Gulp?
Automate and enhance your workflow
不仅仅是自动化的构建工具
为什么使用Gulp
懒
自动化构建
提升代码质量
好钢用在刀刃上 (专注于代码)
早下班
升职加薪
…
有哪些东西可以自动化?
- 代码分析 (jsHint, jsCs, eslinet, cssLint)
-
编译
-
sass, less -> css
-
vendor-prefix
-
es6, typeScript, coffee -> js
-
- 拼接文件(css, js)
-
压缩 (css, 图片, 雪碧图, 图标SVG)
-
混淆 (uglify)
-
sourcemaps
-
立即执行函数
-
Angular(templateCache, 依赖注入)
-
HTML生成 引用的注入(css,js)
-
文件重命名
-
全局文本的替换
-
版本号 文件hash;
-
测试
-
删除文件
-
文档自动生成
-
自动上传, 部署
-
git commit hook (commit记录的格式化)
-
其他:
- 源文件有哪些?
-
生成的文件多大?
-
生成的文件版本号汇总?
-
开发阶段出错系统提示?
上述的一切 都可以使用Gulp自动化完成
而且可以快的让你飞起来!
Automate and enhance your workflow
work smarter, not harder
Gulp vs Grunt




简单总结
-
Gulp是基于代码的, Grunt是基于配置的
-
Gulp是基于流的, Grunt是基于文件的
-
基于代码可以借助node模块, 更加灵活
-
更加简洁
-
更好的debug
-
快 [微笑]
如何使用
在Gulp4.0之前, Gulp一共只有4个API:
- gulp.src - 获得后续操作的文件流
- gulp.dest - 输出文件
- gulp.task - 定义gulp任务
- gulp.watch - 监听文件变化
Gulp4.0不向下兼容, 共8个API
- gulp.task - 定义gulp任务
- gulp.src - 获得后续操作的文件流
- gulp.dest - 输出文件
- gulp.parallel - 生成并行任务
- gulp.series - 生成串行任务
- gulp.watch - 监听文件变化
- gulp.symlink - 输出文件(生成软连接)
- gulp.lastRun - 获得上次执行某任务的时间戳
- gulp.tree - 获得gulp任务的树结构
- gulp.registry - 注册任务
经笔者实践, Gulp4.0的API简化了任务间的依赖关系
思维复杂度降低
因此
我会按照Gulp4.0的API进行讲解
注意 Gulp 4.0 尚未正式发布
所以在项目中安装依赖的时候, 写法稍微有点不同:
npm install --save-dev gulpjs/gulp#4.0
gulp.task([name,] fn)
定义Gulp任务
// name: gulp任务的名字, 如果不提供, 将用 fn.name 或者 fn.displayName 来作为任务的名字
// fn: 异步函数; fn 可以接收一个callback, 在异步操作结束后调用;
// 或者 fn可以返回一个 promise, stream, child process, RxJS observable 以示任务结束
// fn.name, fn.displayName. 由于fn.name不可修改,
// 针对匿名函数可以提供一个 displayName属性来充当任务的名称
// fn.description 使用 gulp --tasks 时, 此字段会出现在task的名字后面
//
gulp.task('task', function someTask(done) {
// 1. done(); 后续举例
// 2. return a promise; 后续举例
// 3. return stream; 后续举例
// 4. return child process; 未研究
// 5. return RxJs observable; 未研究
});
function taskName() {}
gulp.task(taskName);
小试牛刀
$ gulp hello
[19:37:48] Using gulpfile ~/Tech/workspace/github/automating-your-workflow-with-gulp/demo/gulpfile.js
[19:37:48] Starting 'hello'...
hello
[19:37:48] Finished 'hello' after 1.89 ms
var gulp = require('gulp');
gulp.task('hello', function (done) {
console.log('hello');
done(); // 显示的调用回调函数表示任务完成; 尝试将这里去掉
});
var del = require('del');
/**
* 删除build目录下的所有文件
*/
gulp.task('clean', function () {
// del操作是一个promise
return del(config.buildDir);
});
gulp.src(globs[, options])
获得后续操作的文件流
// globs: String or Array
// 表示输入文件的通配符, 可以是字符串, 也可以是字符串数组
// 如 gulp.src(['*.js', '!b*.js', 'bad.js'])
gulp.src('globs', {
// cwd, 表示 blobs 的当前目录, 很有用哦!
// Default: process.cwd()
cwd: '',
// base, 表示输入文件的基准地址;
// 默认是第一个通配符前的地址 如: gulp.src('client/js/**/*.js') base 就是 client/js/
// 在保证输出目录结构的时候有用, 后续会讲解
base: '',
// buffer表示文件在内存中的存储形式, 默认是true,
// 如果是false, 那么返回的文件形式将是 file.contents, 大型文件有用, 原理未研究.
buffer: true,
// 文件最后修改时间小于这个值得将会忽略掉
// 这里可以使用 gulp.lastRun, 后续会讲解.
since: 'Date or Number',
// 允许空文件, 否则src不存在的时候会报错
allowEmpty: false,
// 是否真正读取文件, 如果为false, 只有文件的meta信息会被读取, 后续会举例
read: true,
passthrough: false // 没研究
});
注意事项
gulp.src(glob, options) 中的option 还有其他选项, 详细请看:
https://github.com/gulpjs/glob-stream#options
https://github.com/isaacs/node-glob#options
gulp.dest(path[, options])
输出文件
gulp.src('')
// path: String or a function(file) (可以是个函数欧!)
// 输出文件的目录
.pipe(gulp.dest('path', {
// cwd, 当前目录, 只有path是相对路径的时候才会用到
cwd: 'process.cwd()',
// mode, 输出文件的mode,
// 默认和源文件一致 或者 和process的mode一致; 如: "0744", 0744 or 484
mode: 'String or Number',
// dirMode, 输出文件夹的mode
// 默认是process的mode
dirMode: 'String or Number',
// overwrite, 是否覆盖已经存在的文件
overwrite: true
}))
小试牛刀
/**
* 拷贝.css文件到build目录下
*/
gulp.task('css', function () {
// 这里的cwd参数表示css/目录的父级目录;
// 这里的base参数, 是为了保证源目录和生成目录的目录结构一致;
// 可以尝试删除看看有何异同 // 你会发现目录结构被破坏掉了!
return gulp.src('css/**/*.css', {cwd: 'src', base: 'src'})
.pipe(gulp.dest(config.buildDir));
});
gulp.parallel(...tasks) 构造并行任务
gulp.series(...tasks) 构造串行任务
gulp.task('one', function (done) {
done();
});
function two(done) {
done();
}
gulp.task('three', function (done) {
done();
});
function four(done) {
done();
}
gulp.task('five', function (done) {
done();
});
gulp.task('series¶llel', gulp.parallel(
'one',
gulp.series(two, 'three'),
gulp.parallel(four, 'five')
));
gulp.symlink(folder[, options])
与 gulp.dest 功能一致, 只不过是生成软连接
// folder: String or Function(file)
.pipe(gulp.symlink('folder', {
cwd: 'process.cwd()', // 只有path是相对路径的时候才会用到
dirMode: 'String or Number' // 默认是process的mode
}))
gulp.watch(glob[, opts][, fn])
监听文件
// glob: String or Array;
var watcher = gulp.watch('glob', {
ignored: 'glob', // 忽略的文件
usePolling: false, // 一般用于网络文件或者虚拟机里的文件
cwd: '', // glob的base路径
alwaysStat: false // 如果需要 fs.Stats 的所有事件可以设置为true, 稍微影响性能
}, function () {
// do something here
});
// gulp.watch 返回一个 FSWatcher; 可以接收 add, change, unlink 事件
// 函数参数:
// path: 文件的路径, 如果上述opts.cwd指定, path为相对路径
// stats: 一个 fileStat 对象, 可能会被提供; 如果opts.alwaysStat == true, 那么stats一定会被提供;
watcher.on('add|change|unlink|', function (path, stats) {
console.log('File ' + path + ' was added|changed|removed');
});
// watcher的一些方法
watcher.close(); // 关闭文件监听
watcher.add('glob'); // 继续添加监听文件
watcher.unwatch('glob'); // 不再监听glob所代表的文件, 其余继续
举个栗子
var del = require('del');
gulp.task('watch', function () {
var watcher = gulp.watch('css/**/*.css', {cwd: 'src'},
gulp.series('build:css', 'build:inject'));
watcher.on('add', (filePath) => console.log('add', filePath));
watcher.on('change', (filePath) => console.log('change', filePath));
// 当文件删除的时候, 同时删除目标目录下的文件, 这样保证 build:inject 的时候不会引入已经删除的文件
watcher.on('unlink', (filePath) => {
console.log('delete', filePath);
var src = path.relative(path.resolve('src'), filePath);
var dest = path.resolve(config.buildDir, src);
return del(dest);
});
});
跟我一起重写Demo中的gulpfile
目
录
结
构
├── gulpfile.js
├── build/ 生产目录
└── src/ 源文件目录
├── css
│ ├── add.scss
│ ├── delete.scss
│ ├── main.scss
│ └── normalize.css
├── img
│ └── gulp.png
├── index.html
├── js
│ ├── app.js
│ ├── controllers
│ │ ├── add.controller.js
│ │ └── delete.controller.js
│ ├── directives
│ │ ├── add.directive.js
│ │ └── delete.directive.js
│ ├── filters
│ │ ├── lowerCase.js
│ │ └── upperCase.js
│ └── services
│ └── counter.js
├── lib
│ └── angular.js
└── views
├── add.tpl.html
└── delete.tpl.html
任务分析
开发阶段
-
删除build目录下的所有文件
-
拷贝.css文件到build目录下
-
编译.scss文件到build目录下
-
为.js文件添加angular的注解, 且包裹一个立即执行函数,输出到build目录
-
拷贝图片和lib下的文件到build目录
-
将angular的模板文件经ngTemplate处理合并为一个js文件, 输出到build/js目录下
-
将css,js文件插入到index.html中, 注意js的顺序, 输出到build目录下
-
监听以上文件, 并作出增量修改
任务分析
部署阶段
-
CSS
-
将css与编译好的sass文件合并压缩;
-
添加sourcemaps
-
还可以添加诸如autoprefixer等插件
-
-
JS
-
将js文件添加angular注解,和立即执行函数, 和template文件合并压缩;
-
并且生成sourcemaps
-
-
其他静态资源
-
拷贝资源到build目录
-
这里可以根据实际情况对不同的资源进行不同的处理
-
比如对image进行压缩处理等
-
-
Index
-
将css,js文件插入到index.html中, 注意js的顺序, 输出到build目录下
-
用到的插件
var gulp = require('gulp');
var del = require('del');
var inject = require('gulp-inject');
var order = require("gulp-order");
var cleanCSS = require('gulp-clean-css');
var sourcemaps = require('gulp-sourcemaps');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');
var size = require('gulp-size');
var rev = require('gulp-rev');
var htmlmin = require('gulp-htmlmin');
var cached = require('gulp-cached');
var sass = require('gulp-sass');
var iife = require('gulp-iife');
var print = require('gulp-print');
var eventStream = require('event-stream');
var ngAnnotate = require('gulp-ng-annotate');
var ngTemplates = require('gulp-ng-templates');
逐个讲解
还可以做哪些优化?
1. 增量编译
2. 一些钩子
一些好用的插件和recipies
谢谢
小鱼二
跟我一起学Gulp
By xy2
跟我一起学Gulp
- 4,977