
一、快速gulp定位
gulp是学习项目基于流(stream)的自动化构建工具。
二、并接初始化
如果之前已经全局安装了 gulp ,快速请通过运行以下命令来删除旧安装:
npm rm --global gulp 然后通过以下命令安装独立的学习项目gulp-cli
npm i --global gulp-cli 为什么废弃gulp,而改用gulp-cli?并接
想将cli和gulp进行解耦,处理只位于gulp-cli中。快速目的学习项目:
主要是想在减少安全安装包的大小。 与主包gulp分开,并接在不影响gulp-cli流程的快速情况下进行gulp的功能和bug修复 为后续的sips主题,以及向任务中添加自定义元数据和配置文件。学习项目 看一下安装的并接版本2.x
gulp -v CLI version: 2.3.0 Local version: Unknown 三、项目中使用gulp
进入到项目中,快速安装gulp
npm i --save-dev gulp 执行gulp -v
chengxinsong$ gulp -v CLI version: 2.3.0 Local version: 4.0.2 在项目的学习项目根目录下创建gulpfile.js文件,在文件中输入以下内容:
function defaultTask(cb) { cb(); } exports.default = defaultTask; 四、并接gulp基本转化流程
找到src目录下的所有js文件 压缩这些js文件 将压缩js代码输出到dist/js目录下 const gulp = require(gulp); const uglify = require(gulp-uglify); gulp.task(gulpSaucxs, function(done) { gulp.src(src/*.js) // dist与src在共同目录下 .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文件,我们来写最长递增子序列的方法。
// 最长递增子序列 function lis(n) { if (n.length === 0) return 0 // 创建一个和参数相同大小的数组,并填充值为 1 let array = new Array(n.length).fill(1) // 从索引 1 开始遍历,因为数组已经所有都填充为 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 gulpSaucxs gulp后面跟着的是任务的名称,不输入任务名称的话会默认找default任务,找不到会报错
然后在与src同级新增dist/js,然后生成压缩之后index.js文件。
五、逐渐废弃gulp.task()
官网说是这个task的API不再是推荐的模式。
那还是简单提2句,这个api伴随着开发而消失。
gulp.task(name[, deps], fn) name 为任务名 deps 是当前定义的任务需要依赖的其他任务,为一个数组。当前定义的任务会在所有依赖的任务执行完毕后才开始执行。如果没有依赖,则可省略这个参数 fn 为任务函数,我们把任务要执行的代码都写在里面。该参数也是服务器托管可选的。 六、task任务
每个gulp任务task都是一个异步的js函数。接收一个回调函数作为参数,或者是一个返回 stream,promise,event emitter、child process 或 observable 类型值的函数。
我们继续改写上面 gulpSaucxs 的任务。
const gulp = require(gulp); const uglify = require(gulp-uglify); function gulpSaucxs(done) { gulp.src(src/*.js) // dist与src在共同目录下 .pipe(uglify()) .pipe(gulp.dest(dist/js)); // 相对路径 done(); } exports.gulpSaucxs = gulpSaucxs; // gulpSaucxs函数被exports导出是公开任务,可以直接被gulp命令直接调用。 导出的 gulpSaucxs 我们可以直接使用gulp命令来执行。
gulp gulpSaucxs 输出跟最初是一致的。
导出任务
被gulpfile导出export的任务为公开任务,未被导出的任务会被认为是私有任务。
还是在刚才的代码中,我们新增privateTask方法和导出组合任务。
const gulp = require(gulp); const uglify = require(gulp-uglify); function gulpSaucxs(done) { gulp.src(src/*.js) // dist与src在共同目录下 .pipe(uglify()) .pipe(gulp.dest(dist/js)); // 相对路径 done(); } // 新增的私有任务 function privateTask(done) { console.log(hello 「松宝写代码」) } exports.gulpSaucxs = gulpSaucxs; // gulpSaucxs函数被exports导出是公开任务,可以直接被gulp命令直接调用。 exports.composeTask = gulp.series(gulpSaucxs, privateTask); // 导出组合任务 上面的代码中,privateTask 方法就是没有被直接导出的方法,称为私有任务;gulpSaucxs 方法是被导出的方法,称为公共任务。
私有任务的设计主要是为了内部的使用,通常作为gulp.series()和gulp.paralle()组合的组成部分。
这时候我们执行
gulp composeTask 执行结果
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。
const gulp = require(gulp); const uglify = require(gulp-uglify); function gulpSaucxs(done) { gulp.src(src/*.js) // dist与src在共同目录下 .pipe(uglify()) .pipe(gulp.dest(dist/js)); // 相对路径 done(); } // 新增的私有任务 function privateTask(done) { console.log(hello 「松宝写代码」); done(); } exports.gulpSaucxs = gulpSaucxs; // gulpSaucxs函数被exports导出是公开任务,可以直接被gulp命令直接调用。 exports.composeTask = gulp.parallel(gulpSaucxs, privateTask); // 导出组合任务,以最大的并发来运行 执行
gulp cpmposeTask 执行结果
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流
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的例子。
const gulp = require(gulp); function promiseTask(done) { Promise.resolve(返回的值); done(); } exports.promiseTask = promiseTask; 输出:
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 的例子。
// 返回event emitter 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,结果如下:
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 的例子。
// 返回child_process 子进程 const { exec } = require(child_process); function childProcessTask(done) { exec(data); console.log(松宝写代码) done(); } exports.childProcessTask = childProcessTask; 执行 gulp childProcessTask ,结果如下:
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... 松宝写代码 [21:48:32] Finished childProcessTask after 7.02 ms 5、返回 RxJS observable 观察对象
看一个返回 observable 的例子。
// 返回 observable 观察对象 const Observable = require(rx).Observable; function observableTask(done) { Observable.return(松宝写代码); console.log(松宝写代码) done(); } exports.observableTask = observableTask; 执行 gulp observableTask ,结果如下:
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 的参数。
// 返回 callback 回调函数 function callbackTask(done) { console.log(松宝写代码) done(new Error(抛出错误了)); } exports.callbackTask = callbackTask; 执行 gulp callbackTask 结果
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,并使用其他同步代码。
// 使用 async/await 回调函数 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 结果
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 // 实例 const minifycss = require(gulp-minify-css); //压缩css const del = require(del); // 删除目录 // 清空目录 function clean(done) { del([dist/**]); done(); } // 压缩css function minifyCss(done) { gulp.src(src/*.css) .pipe(minifycss()) .pipe(gulp.dest(dist/css)); done() } // 压缩js function uglifyJs(done) { gulp.src(src/*.js) .pipe(uglify()) .pipe(gulp.dest(dist/js)); done(); } exports.exampleGulpTask = gulp.series(clean, gulp.parallel(minifyCss, uglifyJs)); // 执行顺序 clean => 并行执行 css js 压缩