Gulp 4 在任务执行体系上有一个很重要的改动,下面我们一起来看一下这个新的特性和如何从 Gulp 3 迁移到新版本
Gulp 3 中的任务执行链
在了解新特性之前,让我们先看看之前是怎么做的。通常 Gulp 允许给 task 定义依赖(dependency),这保证了 task 执行之前它依赖的 task 已经获得执行。看下面代码:
// 默认任务,执行 scripts 和 styles 这两个任务
gulp.task(‘default’, [‘scripts’, ‘styles’], function() {…});
// scripts 和 styles 任务都调用了 clean 任务
gulp.task(‘styles’, [‘clean’], function() {…});
gulp.task(‘scripts’, [‘clean’], function() {…});
// Clean 任务清空了 build 目录
gulp.task(‘clean’, function() {…});
这是很典型的 Gulpfile 代码,你目的是执行 scripts 任务和 styles 任务,在此之前把 build 输出的目录清空以保证每次都都可以获得最新的 build 结果。这种语法很优雅,跟其他构建工具也类似。
当 Gulp 开始工作,它会创建一个任务依赖树,见下图。它发现 clean 任务是另外两个 task 的依赖,从而确保 clean 只执行一次。
有一点需要注意:所有 task 都以最大并发量执行。它(default task)的执行顺序见下图:首先执行 clean 任务,然后并行执行 scripts 和 styles 任务。
这种方式有一些问题:
一旦你定义了上面的依赖链,依赖链的执行顺序就被确定了。
例如,给其中一个 styles 任务添加了监听(watcher)当 css 文件改变时重新执行 styles 任务,这时候就会出问题。想象一下,你每次改动了 css 文件就会触发 styles 任务,gulp 会首先执行 clean 然后执行 styles。如此一来,你构建打包的文件会因为 clean 任务执行被删除。
目前没有好的办法来顺序执行前面定义的各个 task。“执行某一任务前先执行其依赖的任务”— 这种执行方式导致了前面的问题。
有一个 Gulp 插件用来解决这个问题:run-sequence。它现在已经是 Gulp 4 的一部分了。
Gulp 4 中的任务执行函数
Gulp 4 抛弃了依赖参数(dependency parameter),用执行函数来代替:
gulp.series 用于串行(顺序)执行
gulp.parallel 用于并行执行
上面的两个函数接受两个参数:
要执行的任务的名字
需要执行的函数
如果你想并行执行 scripts 和 styles,你可以这么写:
gulp.task(‘default’, gulp.parallel(‘scripts’, ‘styles’));
更棒的是,gulp.parallel 和 gulp.series 是函数,可以接受其它函数做参数,所以你可以随意嵌套使用它们,从而创建复杂的执行顺序。上图的执行顺序是:A, 然后 B, 然后 C 和 D 并行执行, 最后 E。
从 Gulp 3 迁移到 Gulp 4
尽量让任务以最大并发量执行可以提高执行效率,我们可以考虑把依赖的任务数组替换为 gulp.parallel 函数,最上面的任务代码可以改为像下面这样:
gulp.task(‘styles’, gulp.parallel(‘clean’, function() {…}));
gulp.task(‘scripts’, gulp.parallel(‘clean’, function() {…}));
gulp.task(‘clean’, function() {…});
gulp.task(‘default’, gulp.parallel(‘scripts’, ‘styles’));
这个方法的第一个问题是,执行 scripts 任务和 styles 任务时,clean 任务会先执行。在并发的情况下,这意味着,执行 styles 时,可能把 scripts 任务的输出删掉。我们不想这样,让我们把上面的代码修改一下,使用 gulp.series 来创建串行执行的任务。
gulp.task(‘styles’, gulp.series(‘clean’, function() {…}));
gulp.task(‘scripts’, gulp.series(‘clean’, function() {…}));
gulp.task(‘clean’, function() {…});
gulp.task(‘default’, gulp.parallel(‘scripts’, ‘styles’));
这样好多了,然而还有需要解决的问题。首先,依赖仍然写死在了代码里,我们执行 scripts 或者 styles 时,clean 任务会先被执行。其次,Gulp 4 不会进行依赖检查,我们的执行树(执行 default task)看起来像这样:clean 任务被执行两次,这是致命的,因为有可能上一个任务的执行结果被下一个任务的执行删除。
为了做一次完美的健壮的迁移,实现最初的执行顺序,并且避免写死代码,我们可以这样做:
先来看一下最初的执行顺序:default task 的执行顺序是:先 clean,然后 styles 和 scripts 并行执行。
每一个可以并发进行的步骤可以组合在 gulp.parallel 函数中,其余的任务按顺序放在 gulp.series 函数中,像这样:对应的代码是:
// 去掉了 clean 任务依赖
gulp.task(‘styles’, function() {…});
gulp.task(‘scripts’, function() {…});
gulp.task(‘clean’, function() {…});
// Per default, start scripts and styles
gulp.task(‘default’,
gulp.series(‘clean’, gulp.parallel(‘scripts’, ‘styles’),
function() {…}));
这样一来,default task 的任务执行顺序就跟最初一样了。