什么是gulp?
gulp是前端开发过程中一种基于流的代码构建工具,是自动化项目的构建利器;它不仅能对网站资源进行优化,而且在开发过程中很多重复的任务能够使用正确的工具自动完成;使用它,不仅可以很愉快的编写代码,而且大大提高我们的工作效率。
gulp是基于Nodejs的自动任务运行器, 它能自动化地完成 前端代码的测试、检查、合并、压缩、格式化、浏览器自动刷新、部署文件生成,并监听文件在改动后重复指定的这些步骤。
什么是流?
流,流水,把文件比作河流,那么一条河流流出,另一条河流流进,gulp对于文件流的操作就是这样,一个操作的输出结果作为另一个操作的输入。
gulp 安装
全局安装 gulp:
1
npm install --global gulp
作为项目的开发依赖(devDependencies)安装:
1
npm install --save-dev gulp
在项目根目录下创建一个名为 gulpfile.js 的文件:
1
2
3
4
5
var gulp = require('gulp');
// 默认task
gulp.task('default', () => {
console.log('Hello World')
});
运行 gulp:
1
gulp
默认的名为 default 的任务(task)将会被运行。
想要单独执行特定的任务(task),请输入
1
gulp <task> <othertask>。
tasks 依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
var gulp = require('gulp');
// task1
gulp.task('task1', () => {
console.log('task1');
});
// task2
gulp.task('task2', () => {
setTimeout(() => {
console.log('task2')
}, 1000);
});
// 在执行 default 之前先执行 task1 和 task2
gulp.task('default', ['task1', 'task2'], () => {
console.log('Hello World');
});
输出顺序为:
task1 Hello World task2
流式处理
(1). 在项目根目录下创建 src 文件目录,里面创建 index.js (2). 在项目根目录下创建 dist 文件目录 (3). 安装 gulp-uglify
1
npm install gulp-uglify --save-dev
(4). 使用 gulp 压缩 index.js 并将结果输出
1
2
3
4
5
6
7
8
var gulp = require('gulp');
var uglify = require('gulp-uglify');
// 压缩js
gulp.task('default', () => {
gulp.src('src/*.js')
.pipe(uglify())
.pipe(gulp.dest('dist'))
});
(5). 运行 “gulp” 命令后发现在 dist 目录下生产了压缩后的 index.js
(6). 解释
gulp.src 是输入; gulp.dest 是输出 pipe 是管道的意思,也是 stream 里核心概念,pipe 将上一个的输出作为下一个的输入。src 里所有 js,经过处理1,处理2,变成输出结果,中间的处理 pipe 可以1步,也可以是n步。第一步处理的结果是第二步的输入,以此类推,就像生产线一样,每一步都是一个 task 是不是很好理解呢?
每个独立操作单元都是一个 task,使用 pipe 来组装 tasks,于是 gulp 就变成了基于 task 的组装工具。
gulp.src()
在上面的例子中,gulp.src() 函数用字符串匹配一个文件或者文件的编号(被称为“glob”),然后创建一个对象流来代表这些文件,接着传递给 uglify() 函数,它接受文件对象之后返回有新压缩源文件的文件对象,最后那些输出的文件被输入 gulp.dest()函数,并保存下来。
gulp.src() 可以接收以下类型的参数:
js/app.js 精确匹配文件 js/.js 仅匹配 js 目录下的所有后缀为 .js 的文件 js//.js 匹配 js 目录及其子目录下所有后缀为 .js 的文件 !js/app.js 从匹配结果中排除 js/app.js,这种方法在你想要匹配除了特殊文件之外的所有文件时非常好用 *.+(js|css) 匹配根目录下所有后缀为 .js 或者 .css 的文件
假如 js 目录下包含了压缩和未压缩的 JavaScript 文件,现在我们想要创建一个任务来压缩还没有被压缩的文件,我们需要先匹配目录下所有的 JavaScript 文件,然后排除后缀为 .min.js 的文件:
1
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
babel
babel 用于转化 JavaScript 代码,比如将 ES6 的语法转化成 ES5,或者将 JSX 语法转化为 JavaScript 语法。
假如上文中提到的 index.js 里面的内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
'use strict';
import express, { Router } from 'express';
import bodyParser from 'body-parser';
// 定义app和router
let app = express();
let router = Router();
//中间件
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//路由
router.get('/', (req, res, next) => {
res.end('Hello World!');
});
app.use('/', router);
//启动app
app.listen(3000, () => {
console.log('server listening at port 3000...');
});
使用 babel 转化为 ES5 语法:
(1) 安装 babel-core babel-preset-es2015
1
npm install --save-dev babel-core babel-preset-es2015
(2) 创建 .babelrc 文件, 配置如下
1
2
3
{
“presets”: [“es2015”]
}
(3) 手动使用 babel 转译:
1
$ babel src -d lib
(4) 安装 gulp-babel
1
$ npm install --save-dev gulp-babel
(5) 编写 gulpfile
在根目录新建一个 gulpfile.babel.js 文件。 gulp 原生并不支持 ES6 语法,但是我们可以告诉 gulp 使用 babel 将 gulpfile 转换为 ES5,方法就是将 gulpfile 命名为 gulpfile.babel.js。
(6) 使用 ES6 编写 gulpfile.babel.js
1
2
3
4
5
6
7
8
import gulp from 'gulp';
import babel from 'gulp-babel';
// 语法转化+压缩
gulp.task('default', () => {
gulp.src('src/*.js')
.pipe(babel())
.pipe(gulp.dest('lib'))
});
打开 lib 目录下的 index.js 文件,就可以查看 babel 编译后的 ES5 语法的文件了。
gulp-watch
开始工作以后,每次改动 index.js 都要手动 gulp 一下实在太麻烦了,使用 gulp-watch 可以监听文件变化,当文件被修改之后,自动将文件转换。
(1) 安装 gulp-watch
1
npm install gulp-watch --save-dev
(2) 新增 task
1
2
3
4
5
6
7
8
gulp.task('watch', () => {
gulp.src('src/*.js')
.pipe(watch('src/*.js'), {
verbose: true
})
.pipe(babel())
.pipe(gulp.dest('lib'))
});
(3) 启动 watch task
1
gulp watch
修改 index.js 后 lib/index.js 也会随之改变。(≧∀≦)ゞ
查看全部 tasks
1
2
3
4
5
$ gulp -T
[16:06:54] Requiring external module babel-register
[16:06:54] ├── default
[16:06:54] └── watch
gulp 顺序执行
默认的,task 将以最大的并发数执行,也就是说,gulp 会一次性运行所有的 task 并且不做任何等待。如果你想要创建一个序列化的 task 队列,并以特定的顺序执行,需要做两件事:
- 给出一个提示,来告知 task 什么时候执行完毕,
- 并且再给出一个提示,来告知一个 task 依赖另一个 task 的完成。
假如我想要 task1 执行完成后再执行 task2, 可以用以下三种方式:
直接返回一个流
1
2
3
gulp.task('task1', function () {
return gulp.watch('src/*.js');
});
//只要加一个return就好了
返回一个promise
1
2
3
4
5
6
7
8
9
10
gulp.task('task1', function () {
var Q = require('q');
var deferred = Q.defer();
// do async stuff
setTimeout(function () {
deferred.resolve();
}, 1);
return deferred.promise;
});
使用回调callback
task 的执行函数其实都有个回调,我们只需要在异步队列完成的时候调用它就好了。
1
2
3
4
5
6
7
gulp.task('task1', function (cb) {
// do async stuff
setTimeout(function () {
cb()
}, 1);
});
所以只要依赖的任务是上面三种情况之一,就能保证当前任务在依赖任务执行完成后再执行。这边需要注意的是依赖的任务相互之间还是并行的。需要他们按顺序的话。记得给每个依赖的任务也配置好依赖关系。
1
2
3
4
5
6
7
8
9
10
11
12
var gulp = require('gulp');
gulp.task('one', () => {
console.log('one');
});
// two 依赖 one
gulp.task('two', ['one'], () => {
console.log('two');
});
// default 依赖 one,two
gulp.task('default', ['one', 'two'], () => {
console.log('default');
});