本文主要介绍:
gulp定位
gulp初始化
项目中使用gulp
gulp基本转化流程
逐渐废弃gulp.task()
task任务
异步执行
一、gulp定位
gulp是基于流(stream)的自动化构建工具。
二、初始化 如果之前已经全局安装了 gulp ,请通过运行以下命令来删除旧安装:
然后通过以下命令安装独立的gulp-cli
为什么废弃gulp,而改用gulp-cli?
想将cli和gulp进行解耦,处理只位于gulp-cli中。目的:
主要是想在减少安全安装包的大小。
与主包gulp分开,在不影响gulp-cli流程的情况下进行gulp的功能和bug修复
为后续的sips主题,以及向任务中添加自定义元数据和配置文件。
看一下安装的版本2.x
1 2 3 gulp -v CLI version : 2.3 .0 Local version : Unknown
三、项目中使用gulp 进入到项目中,安装gulp
执行gulp -v
1 2 3 chengxinsong$ gulp -v CLI version : 2.3 .0 Local version : 4.0 .2
在项目的根目录下创建gulpfile.js文件,在文件中输入以下内容:
1 2 3 4 function defaultTask (cb ) { cb (); } exports .default = defaultTask;
四、gulp基本转化流程
1、找到src目录下的所有js文件
2、压缩这些js文件
3、将压缩js代码输出到dist/js目录下
1 2 3 4 5 6 7 8 9 const gulp = require ('gulp' );const uglify = require ('gulp-uglify' );gulp.task ('gulpSaucxs' , function (done ) { gulp.src ('src/*.js' ) .pipe (uglify ()) .pipe (gulp.dest ('dist/js' )); done (); })
上面代码中,task方法接收的是任务代码,接收的必须有回调函数,gulp.src()
方法去找src目录下的js文件,.pipe
是接收一个流的结果,并返回一个处理后流的结构,pipe
方法中执行uglifg()
方法用来压缩js代码。gulp.dest()
方法输出到指定相对目录下。done()
方法就是回调函数执行。
gulp.task(‘任务名’, 回调函数),任务名也是后续gulp 任务名,执行这个任务,回调函数中处理这个任务需要处理的代码。
src() 方法读取文件生成一个Node流(stream),它将所有匹配的文件读取到内存中并通过流(stream)进行处理。
Node流(stream)所提供的主要API方法pipe()方法。
dest()方法接收一个输出目录作为参数,将文件内容以及文件属性写入到指定的目录中。
我们在src下新建一个index.js
文件,我们来写最长递增子序列的方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 function lis (n ) { if (n.length === 0 ) return 0 let array = new Array (n.length ).fill (1 ) for (let i = 1 ; i < n.length ; i++) { for (let j = 0 ; j < i; j++) { if (n[i] > n[j]) { array[i] = Math .max (array[i], 1 + array[j]) } } } let res = 1 for (let i = 0 ; i < array.length ; i++) { res = Math .max (res, array[i]) } return res }
输出的已经通过gulp处理的index.js
的方法
我们在与gulpfile.js的同级目录下执行gulp task的名称
gulp后面跟着的是任务的名称,不输入任务名称的话会默认找default任务,找不到会报错
然后在与src同级新增dist/js,然后生成压缩之后index.js文件。
五、逐渐废弃gulp.task() 官网说是这个task的API不再是推荐的模式。
那还是简单提2句,这个api伴随着开发而消失。
1 gulp.task (name[, deps], fn)
name 为任务名
deps 是当前定义的任务需要依赖的其他任务,为一个数组。当前定义的任务会在所有依赖的任务执行完毕后才开始执行。如果没有依赖,则可省略这个参数
fn 为任务函数,我们把任务要执行的代码都写在里面。该参数也是可选的。
六、task任务 每个gulp任务task都是一个异步的js函数。接收一个回调函数作为参数,或者是一个返回 stream,promise,event emitter、child process 或 observable 类型值的函数。
我们继续改写上面 gulpSaucxs 的任务。
1 2 3 4 5 6 7 8 9 10 11 const gulp = require ('gulp' );const uglify = require ('gulp-uglify' );function gulpSaucxs (done ) { gulp.src ('src/*.js' ) .pipe (uglify ()) .pipe (gulp.dest ('dist/js' )); done (); } exports .gulpSaucxs = gulpSaucxs;
导出的 gulpSaucxs 我们可以直接使用gulp命令来执行。
输出跟最初是一致的。
导出任务 被gulpfile导出export的任务为公开任务,未被导出的任务会被认为是私有任务。
还是在刚才的代码中,我们新增privateTask方法和导出组合任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const gulp = require ('gulp' );const uglify = require ('gulp-uglify' );function gulpSaucxs (done ) { gulp.src ('src/*.js' ) .pipe (uglify ()) .pipe (gulp.dest ('dist/js' )); done (); } function privateTask (done ) { console .log ('hello 「不想写代码」' ) } exports .gulpSaucxs = gulpSaucxs; exports .composeTask = gulp.series (gulpSaucxs, privateTask);
上面的代码中,privateTask 方法就是没有被直接导出的方法,称为私有任务;gulpSaucxs 方法是被导出的方法,称为公共任务。
私有任务的设计主要是为了内部的使用,通常作为gulp.series()和gulp.paralle()组合的组成部分。
这时候我们执行
执行结果
1 2 3 4 5 6 7 8 9 gulp-test chengxinsong$ gulp composeTask [16 :14 :52 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [16 :14 :52 ] Starting 'composeTask' ... [16 :14 :52 ] Starting 'gulpSaucxs' ... [16 :14 :52 ] Finished 'gulpSaucxs' after 8.32 ms [16 :14 :52 ] Starting 'privateTask' ... hello 「不想写代码」 [16 :14 :52 ] Finished 'privateTask' after 1.21 ms [16 :14 :52 ] Finished 'composeTask' after 12 ms
我们看日志,series方法是按照顺序执行,同步执行。
先启动公共任务 composeTask,
开启 gulpSaucxs 任务方法
完成 gulpSaucxs 任务方法
然后8.32毫秒之后
开启 privateTask 任务方法
输出 hello 「不想写代码」
完成 privateTask 任务方法
然后1.21毫秒之后
完成 公共任务 composeTask,
组合任务 gulp提供了2个强大的组合方法:series() 和 parallel(),允许将多个独立的任务组合为一个更强大的操作。
特点:
都可以接受任意数目的任务Task函数或者已经组合的操作
series()方法和parallel()方法 可以相互嵌套任意深度
我们把上面的例子的series方法换成parallel。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const gulp = require ('gulp' );const uglify = require ('gulp-uglify' );function gulpSaucxs (done ) { gulp.src ('src/*.js' ) .pipe (uglify ()) .pipe (gulp.dest ('dist/js' )); done (); } function privateTask (done ) { console .log ('hello 「不想写代码」' ); done (); } exports .gulpSaucxs = gulpSaucxs; exports .composeTask = gulp.parallel (gulpSaucxs, privateTask);
执行
执行结果
1 2 3 4 5 6 7 8 9 chengxinsong$ gulp composeTask [18 :24 :35 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [18 :24 :35 ] Starting 'composeTask' ... [18 :24 :35 ] Starting 'gulpSaucxs' ... [18 :24 :35 ] Starting 'privateTask' ... [18 :24 :35 ] Finished 'gulpSaucxs' after 8.24 ms hello 「不想写代码」 [18 :24 :35 ] Finished 'privateTask' after 9.71 ms [18 :24 :35 ] Finished 'composeTask' after 12 ms
我们可以输出日志,可以知道parallel方法是并行的执行任务
先启动公共任务 composeTask,
开启 gulpSaucxs 任务方法
开启 privateTask 任务方法
完成 gulpSaucxs 任务方法
然后8.24毫秒之后
输出 hello 「不想写代码」
完成 privateTask 任务方法
然后9.71毫秒之后
完成 公共任务 composeTask
七、异步执行 当从任务(task)中返回 stream、promise、event emitter、child process 或 observable 时,成功或错误值将通知 gulp 是否继续执行或结束。如果任务(task)出错,gulp 将立即结束执行并显示该错误。
1、返回stream流 1 2 3 4 5 6 7 8 9 10 const gulp = require ('gulp' );const uglify = require ('gulp-uglify' );function streamTask (done ) { return gulp.src ('src/*.js' ) .pipe (uglify ()) .pipe (gulp.dest ('dist/js' )); done (); } exports .streamTask = streamTask;
输出:dist/js/index.js
2、返回promise 看一个返回promise的例子。
1 2 3 4 5 6 7 const gulp = require ('gulp' );function promiseTask (done ) { Promise .resolve ('返回的值' ); done (); } exports .promiseTask = promiseTask;
输出:
1 2 3 4 5 chengxinsong$ gulp promiseTask [19 :20 :37 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [19 :20 :37 ] Starting 'promiseTask' ... [19 :20 :37 ] Finished 'promiseTask' after 1.55 ms 返回的值 「不想写代码」公众号
3、返回 eventEmitter 事件发射器 看一个返回 eventEmitter 的例子。
1 2 3 4 5 6 7 8 9 10 11 const { EventEmitter } = require ('events' );function eventEmitterTask (done ) { const emitter = new EventEmitter (); setTimeout (() => { emitter.emit ('data' ) console .log (emitter, '不想写代码' ) }, 500 ); done (); } exports .eventEmitterTask = eventEmitterTask;
执行 gulp eventEmitterTask,结果如下:
1 2 3 4 5 6 7 8 9 10 chengxinsong$ gulp eventEmitterTask [21 :42 :26 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [21 :42 :26 ] Starting 'eventEmitterTask' ... [21 :42 :26 ] Finished 'eventEmitterTask' after 1.77 ms EventEmitter { _events : [Object : null prototype] {}, _eventsCount : 0 , _maxListeners : undefined , [Symbol (kCapture)]: false } 不想写代码
4、返回 child process 子进程 看一个返回 childProcess 的例子。
1 2 3 4 5 6 7 8 const { exec } = require ('child_process' );function childProcessTask (done ) { exec ('data' ); console .log ('不想写代码' ) done (); } exports .childProcessTask = childProcessTask;
执行 gulp childProcessTask ,结果如下:
1 2 3 4 5 chengxinsong$ gulp childProcessTask [21 :48 :32 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [21 :48 :32 ] Starting 'childProcessTask' ... aa写代码 [21 :48 :32 ] Finished 'childProcessTask' after 7.02 ms
5、返回 RxJS observable 观察对象 看一个返回 observable 的例子。
1 2 3 4 5 6 7 8 const Observable = require ('rx' ).Observable ;function observableTask (done ) { Observable .return ('不想写代码' ); console .log ('不想写代码' ) done (); } exports .observableTask = observableTask;
执行 gulp observableTask ,结果如下:
1 2 3 4 5 chengxinsong$ gulp observableTask [21 :53 :14 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [21 :53 :14 ] Starting 'observableTask' ... 不想写代码 [21 :53 :14 ] Finished 'observableTask' after 2.28 ms
6、使用 callback 回调函数 看一个使用 callback 回调函数 的例子。
如果任务(task)不返回任何内容,则必须使用 callback 来指示任务已完成。
如需通过 callback 把任务(task)中的错误告知 gulp,将 Error 作为 callback 的参数。
1 2 3 4 5 6 function callbackTask (done ) { console .log ('不想写代码' ) done (new Error ('抛出错误了' )); } exports .callbackTask = callbackTask;
执行 gulp callbackTask 结果
1 2 3 4 5 6 7 chengxinsong$ gulp callbackTask [21 :58 :22 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [21 :58 :22 ] Starting 'callbackTask' ... 不想写代码 [21 :58 :22 ] 'callbackTask' errored after 2.09 ms [21 :58 :22 ] Error : 抛出错误了 at callbackTask
7、使用 async/await 看一个使用 async/await 异步函数 的例子。
可以将任务(task)定义为一个 async 函数,它将利用 promise 对你的任务(task)进行包装。这将允许你使用 await 处理 promise,并使用其他同步代码。
1 2 3 4 5 6 7 8 9 10 const fs = require ('fs' );async function asyncTask (done ) { const { version } = fs.readFileSync ('package.json' ); console .log (version, 'version=====' ) const data = await Promise .resolve ('不想写代码' ); console .log (data, '不想写代码=========' ) done (); } exports .asyncTask = asyncTask;
执行 gulp asyncTask 结果
1 2 3 4 5 6 chengxinsong$ gulp asyncTask [22 :26 :06 ] Using gulpfile ~/Desktop/ coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js [22 :26 :06 ] Starting 'asyncTask' ... undefined version=====不想写代码 不想写代码========= [22 :26 :06 ] Finished 'asyncTask' after 2.02 ms
八、我们来看一个实例 比如我们需要
首先清空dist目录,使用series处理
然后 压缩css和压缩js 并行进行处理,使用parallel处理
输出到dist/js和dist/css
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const minifycss = require ('gulp-minify-css' ); const del = require ('del' ); function clean (done ) { del (['dist/**' ]); done (); } function minifyCss (done ) { gulp.src ('src/*.css' ) .pipe (minifycss ()) .pipe (gulp.dest ('dist/css' )); done () } function uglifyJs (done ) { gulp.src ('src/*.js' ) .pipe (uglify ()) .pipe (gulp.dest ('dist/js' )); done (); } exports .exampleGulpTask = gulp.series (clean, gulp.parallel (minifyCss, uglifyJs));
gulp –require @esbuild-kit/cjs-loader -f gulpfile.ts