这是我参与更文挑战的第14天,活动详情查看: 更文挑战
前言
在这之前,我已经写好了一系列有关 webpack5 的文章(新手向),webpack5 可谓是现在的最流行的前端构建工具,生态完整,有各种 plugin 和 loader 可以实现各种功能。
但是除了 webpack,还有没有其他的构建工具可以用?
当然有,gulp 就是其中之一。
gulp 与 webpack 的根据依赖来管理资源不同,gulp 是流水线性化管理资源,着重于控制整个打包构建过程,使用流式(stream)处理整个构建过程。gulp 相比 webpack 而言,gulp 更加容易理解以及使用简单。
但很遗憾,gulp 只是一个流水性加工工厂,它自身无法处理模块化,尽管它可以将模块化任务交给 webpack-stream
(其实就是 webpack,与 gulp 集成) 来处理,但是一边使用流水性管理资源,一边使用模块化管理资源,这种不伦不类的开发风格实在太诡异(后面文章会有介绍)。
因此如果你确定你的项目需要使用模块化,那么我不建议你使用 gulp,webpack 是更好的选择。当然如果你确定你的模块化依赖于浏览器原生 esm,不需要考虑浏览器兼容性,使用 gulp 也是可以走得通,不过我还是不建议这样做。
本系列将分多篇文章,逐一介绍 gulp 的使用。
本系列比较新手向,适合从来没有使用过 gulp 或略知一二的人看,不适合希望深入 gulp 的人看。
安装
如果你没有安装 node,请先移步安装 node。
新建一个项目 gulp-demo,进入项目目录,初始化。
npm init
复制代码
全局安装 gulp-cli,再本地安装 gulp。
npm install gulp-cli -g
npm install gulp -D
复制代码
在本地项目根目录,运行以下命令,创建 gulpfile.js(其实你也可以自己手动新建文件)
npx -p touch nodetouch gulpfile.js
复制代码
gulpfile.js 即是 gulp 的配置文件,在里面需要用原生 js 去写配置,当运行 gulp
命令时,会自动加载此配置文件。
事实上,官方文档也有提到可以用 typescript、babel 等需要转译语言来写配置文件,文件名则分别为 gulpfile.ts
和 gulpfile.babel.js
。不过个人建议还是用纯 js 版本吧。
任务
在 gulpfile.js 配置文件里,我们需要配置一个个任务来完成管理资源的工作,其中任务分为私有任务、公有任务和组合任务。
公有任务
我们在 gulpfile.js 写上一个函数。
// 公有任务
function publicTask(cb) {
console.log('公有任务')
cb()
}
exports.publicTask = publicTask
复制代码
导出 publicTask
,即可使用命令 gulp publicTask
运行 publicTask
任务。
运行
gulp publicTask
复制代码
publicTask
函数就是公有任务,因为它是暴露出去的,可以在终端使用命令 gulp publicTask
来调用。
记得导出什么就用什么来调用,比如:exports.aa = publicTask
,则用 gulp aa
来调用 publicTask
任务。
注意:上面的 cb 参数是指 callback 回调函数,如果任务不返回任何内容,必须调用 cb 回调来表明任务执行成功,否则将会报错。
私有任务
我们再在 gulpfile.js 写上一个“私有任务”函数。
...
// 私有任务
function privateTask(cb) {
console.log('私有任务')
cb()
}
...
exports.default = privateTask
复制代码
这里的导出 default 是一个 privateTask
函数,运行 gulp
命令会默认调用这个函数。
运行命令
gulp
复制代码
我们可以看到“私有任务”打印在终端上。
privateTask
是一个私有任务,因为它只能通过 gulp
调用,它没有像 publicTask
可以通过 gulp publicTask
调用。
看起来公有任务和私有任务的界限有些不够清楚,但在实际开发中,其实我们并不需要搞清他们的界限,知道如何去暴露和调用就可以了。
组合任务
组合任务分为“串行任务”和“并行任务”。
串行任务
串行任务就是按顺序依次执行任务,gulp.series
是用来处理串行任务。
我们把之前的 exports.default 修改一下,使用 gulp.series
方法。
gulpfile.js
const { series } = require('gulp')
...
// exports.default = privateTask
exports.default = series(privateTask, publicTask)
复制代码
运行命令
gulp
复制代码
可以看到“私有任务”先打印了出来,“公有任务”后打印出来,可以看出,gulp.series
的执行任务顺序是从左到右或从上到下。
并行任务
并行任务则是多个任务同时执行,gulp.parallel
是用来处理并行任务。
gulpfile.js
// exports.default = gulp.series(privateTask, publicTask)
exports.default = gulp.parallel(privateTask, publicTask)
复制代码
下面贴出“串行任务”和“并行任务”的比较,似乎“并行任务”执行所用的时间会短一点。
串行任务与并行任务的任意组合
当然,组合任务的使用方法并不止上述这么简单使用,实际上我们可以混用串行任务和并行任务,例如:
exports.default = series(privateTask, publicTask, parallel(privateTask, series(publicTask)))
复制代码
旧版本的任务
在旧版本的 gulp,我们使用 task
方法将函数注册为任务,例如:
const { series, task } = require('gulp')
task('privateTask', function(cb) {
console.log('私有任务')
cb()
})
task('default', series('privateTask'))
复制代码
现在新版本的 gulp 虽然支持旧版本的 task
,但多以 exports
为注册方式为主,建议使用新版本的方式。
读取文件和输出文件
gulp 有两个方法用于处理文件,一个是 src
,另一个是 dest
,这两个方法分别用来读取文件和输出文件。
我们先在项目根目录下创建一个 src 目录,创建一个 index.html 文件。
为了防止之前的代码骚扰,我们先把 gulpfile.js 的代码注释或删掉,重新写过代码
在 gulpfile.js 配置。
const { series, parallel, src, dest } = require('gulp')
function html() {
return src('src/**/*.html')
.pipe(dest('dist'))
}
exports.build = series(html)
复制代码
运行以下命令
gulp build
复制代码
可以发现在目录里多了一个 dist 目录,并且里面有一个 index.html 文件。
上述代码的 src
就是用来读取 src 目录里的所有 html 文件,将文件转换成流,然后 dest
就是用来将流转换为文件输出到目标路径。
管道
在上面的小节里还用到了 pipe
方法,pipe
即是管道,管道是用于连接“转换流”或者“可写流”,比如上一小节的 pipe
就是用来连接 dest
的转换流(将流转换为文件)。
总之,你可以简单认为管道是流的一个载体,我们需要处理流的内容时或将流转换为文件时,都需要使用管道。
在后面的文章里,将会使用大量的管道,在后面的代码里,你将会更加理解管道这一概念。