升级到 gulp 4.0

升级到 gulp 4.0

笔记本约 1.5 千字

早在 2015 年 5 月 gulpjs 开发团队就已经释出了 4.0 分支,但是直到现在,你执行 npm i gulp 时依然默认安装更稳定的 gulp@3.9.1。然而 gulp@3.9.1 存在高危漏洞,而 npm audit fix 时就升级到了 gulp@4,所以我就 gulp 升级顺手水一篇文章。

安装 gulp 4.0

当 2015 年 gulp 4.0 刚释出的时候还只能通过 GitHub 安装;如今三年过去了,gulp 4.0 已经发布到 NPM,只需在项目中执行 npm i gulp@4 即可安装。

接下来介绍一下 gulp 4.0 的主要变化——

Default 任务指定

之前用 gulp 3.x 时指定 Default Task 的写法一般是这样:

gulp.task('default', ['build']);

但是 gulp 4.0 取消了 gulp.task 的三个参数的用法,所以在 gulp 4.0 时再这么写就会遇到如下报错:

AssertionError [ERR_ASSERTION]: Task function must be specified

所以我们可以运用 gulp 4.0 引入的 gulp.parallel 的方法:

gulp.task('default', gulp.parallel('build'));

如果 Default Task 有多个任务(比如先 cleanbuild),以前会这么写来保证 cleanbuild 之前执行:

gulp.task('clean-build', ['clean'], function(){
    gulp.start('build');
});

但是借助 gulp.series 我们就可以有更清晰的写法:

gulp.task('clean-build', gulp.series('clean', 'build'));

对于 gulp.seriesgulp.parallel 接下来我们会详细谈谈,不过在这之前,先看看 gulp 4.0 是如何简化注册 Task 的流程的。

注册 Task 的新方法

如果想要使用 gulp taskname 的方法执行任务,需要使用 gulp.task 方法注册这个任务;同时 gulpjs 官方又推荐我们每一个任务只做一件事情。但是当类似于 build 这种复杂的任务经常会包含各种子任务,每个子任务都需要使用 gulp.task 进行注册。这无疑大大复杂化了 gulpfile.js 、提升了维护的难度。

在 gulp 4.0 中,gulp.task 又增加了一种新的用法,可以传递一个具名函数作为参数,gulp 会自动为其注册一个 taskname。这样意味着,以前需要这样写的任务:

gulp.task('compile',  function()  {
    gulp.src('./src/*.js')
    .pipe(uglify())
    .pipe(gulp.dest('./dist/js'))
});

现在只需要这样:

function compile() {
    gulp.src('./src/*.js')
        .pipe(uglify())
        .pipe(gulp.dest('./dist/js'))
}
gulp.task(compile);

gulpjs 官方在 gulp 4.0 的更新日志里描述道:除非这个任务需要使用 gulp taskname 调用,否则不再建议使用 gulp.task 注册。

更酷的是,在工作流中调用子任务时,你可以不使用 gulp.task 去调用具名函数,而是直接在 gulp 的工作流中直接引用函数。具体用法我会和下面的例子一起介绍。不过还是先让我介绍一下带来解放的两个革命性的新工具:

Series 和 Parallel

一个复杂的构建流程就像一条电路有并联也有串联,又同时会包含异步和同步执行的任务。过去我们需要依赖 run-sequenceevent-stream 模块才能解决问题,但是无疑这依然是颇为令人诟病和各种不爽,以至于在经过 热烈的社区讨论(其实也没啥讨论啦基本就是大家大拇指 emoji 和举起双手热烈赞成啥的)之后,gulp 4.0 重构了 Task 流程,新增了革命性的 gulp.series(按顺序执行)和 gulp.parallel(同时执行)的 API,现有的任务流程控制迎来了翻天覆地的变革,我以下图所示的一个流程为例进行说明。

gulp-task-example.png

这是一个常见的构建流程。如果你使用的是 gulp 3.9.1 来实现上面的流程,首先每一步都需要注册一个 task:

gulp.task('clean-dev', () => { /* TODO */ });
gulp.task('clean-dist', () => { /* TODO */ });
gulp.task('sprite', () => { /* TODO */ });
gulp.task('compile-css', () => { /* TODO */ });
gulp.task('compile-js', () => { /* TODO */ });
gulp.task('copy-html', () => { /* TODO */ });
gulp.task('reversion', () => { /* TODO */ });
gulp.task('replace', () => { /* TODO */ });

我们需要借助 run-sequence 等第三方模块把他们组合起来:

gulp.task('compile-css',  ['sprite']);
gulp.task('dev',  ['clean-dev'],  function()  {
    runSecquence(['compile-css',  'compile-js',  'copy-html']);
});

gulp.task('md5',  ['dev',  'clean-dist'],  function()  {
    runSecquence('reversion');
});

gulp.task('dist',  ['md5'],  function()  {
    runSecquence('replace');
});

gulpjs 团队推荐一个任务只做一件事情,但是随着流程越来越复杂、划分越来越细,需要注册的 Task 也越来越多,而且同步和异步的任务之间需要用一个额外的中间任务来进行过渡……

但是有了 gulp 4.0,一切都会变得异常简单:

function cleanDev() { /* TODO */ }
function cleanDist() { /* TODO */ }
function sprite() { /* TODO */ }
function compileCss() { /* TODO */ }
function compileJs() { /* TODO */ }
function copyHtml() { /* TODO */ }
function reversion() { /* TODO */ }
function replace() { /* TODO */ }

exports.cleanDev = cleanDev;
exports.cleanDist = cleanDist;
exports.sprite = sprite;
exports.compileCss = compileCss;
exports.compileJs = compileJs;
exports.copyHtml = copyHtml;
exports.reversion = reversion;
exports.replace = replace;

gulp.task('dist',  gulp.series(
    gulp.parallel(
        gulp.series(
            cleanDev,
            gulp.parallel(
                gulp.series(
                    sprite,
                    compileCss
                ),
                compileJs,
                copyHtml
            )
        ),
        cleanDist
    ),
    reversion,
    replace
));

是不是非常清晰易懂?你甚至可以不需要流程图、只需要上面的 gulpfile.js ,就可以看明白整个构建流程。

迁移 gulp 3.x 到 gulp 4.0

gulp 4.0 带来许多焕然一新的改动,除了 gulp.seriesgulp.parallel 两个革命性的 API、支持使用具名函数注册 task 以外,还带来了 gulp.tree gulp.registry ,加上 gulp 4.0 还修复了一大堆 gulp 3.x 遗留下来的高危漏洞,意味着如果你现在的项目还在使用 gulp 3.x,是时候更新到 gulp 4.0 了。

迁移旧有的项目到 gulp 4.0 并不困难,因为除了 gulp.task 不再支持三参数传递以外,gulp 4.0 向下兼容。所以你只需要像前文简单修改一下 gulp.task 的注册方法即可完成对现有的项目的迁移。但是为了发挥出 gulp 4.0 的强大能力,还是建议阅读一下 官方升级日志gulp 4.0 API docs,然后重新编写你的 gulpfile.js 吧!

如果你想要一个 DEMO,这里是 「Suka」主题官网 使用的 gulpfile.js,基于 gulp 4.0。

升级到 gulp 4.0
本文作者
Sukka
发布于
2018-08-29
许可协议
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!
如果你喜欢我的文章,或者我的文章有帮到你,可以考虑一下打赏作者
评论加载中...