快速学习Gulp并接入到项目中

开发 开发工具
gulp是一个自动化构建工具,主要用来设定程序自动处理静态资源的工作。简单的说,gulp就是用来打包项目的。

[[416090]]

一、gulp定位

gulp是基于流(stream)的自动化构建工具。

二、初始化

如果之前已经全局安装了 gulp ,请通过运行以下命令来删除旧安装:

  1. npm rm --global gulp 

然后通过以下命令安装独立的gulp-cli

  1. npm i --global gulp-cli 

为什么废弃gulp,而改用gulp-cli?

想将cli和gulp进行解耦,处理只位于gulp-cli中。目的:

  • 主要是想在减少安全安装包的大小。
  • 与主包gulp分开,在不影响gulp-cli流程的情况下进行gulp的功能和bug修复
  • 为后续的sips主题,以及向任务中添加自定义元数据和配置文件。

看一下安装的版本2.x

  1. gulp -v 
  2. CLI version: 2.3.0 
  3. Local version: Unknown 

三、项目中使用gulp

进入到项目中,安装gulp

  1. npm i --save-dev gulp 

执行gulp -v

  1. chengxinsong$ gulp -v 
  2. CLI version: 2.3.0 
  3. Local version: 4.0.2 

在项目的根目录下创建gulpfile.js文件,在文件中输入以下内容:

  1. function defaultTask(cb) { 
  2.   cb(); 
  3. exports.default = defaultTask; 

四、gulp基本转化流程

  1. 找到src目录下的所有js文件
  2. 压缩这些js文件
  3. 将压缩js代码输出到dist/js目录下
  1. const gulp = require('gulp'); 
  2. const uglify = require('gulp-uglify'); 
  3. gulp.task('gulpSaucxs'function(done) { 
  4.   gulp.src('src/*.js')   // dist与src在共同目录下 
  5.   .pipe(uglify()) 
  6.   .pipe(gulp.dest('dist/js'));   // 相对路径 
  7.   done(); 
  8. }) 

上面代码中,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. function lis(n) { 
  3.   if (n.length === 0) return 0 
  4.   // 创建一个和参数相同大小的数组,并填充值为 1 
  5.   let array = new Array(n.length).fill(1) 
  6.   // 从索引 1 开始遍历,因为数组已经所有都填充为 1 了 
  7.   for (let i = 1; i < n.length; i++) { 
  8.     for (let j = 0; j < i; j++) { 
  9.       if (n[i] > n[j]) { 
  10.         array[i] = Math.max(array[i], 1 + array[j]) 
  11.       } 
  12.     } 
  13.   } 
  14.   let res = 1 
  15.   for (let i = 0; i < array.length; i++) { 
  16.     res = Math.max(res, array[i]) 
  17.   } 
  18.   return res 

输出的已经通过gulp处理的index.js的方法

我们在与gulpfile.js的同级目录下执行gulp task的名称

  1. gulp gulpSaucxs 

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. const gulp = require('gulp'); 
  2. const uglify = require('gulp-uglify'); 
  3. function gulpSaucxs(done) { 
  4.   gulp.src('src/*.js')   // dist与src在共同目录下 
  5.   .pipe(uglify()) 
  6.   .pipe(gulp.dest('dist/js'));   // 相对路径 
  7.   done(); 
  8. exports.gulpSaucxs = gulpSaucxs;   // gulpSaucxs函数被exports导出是公开任务,可以直接被gulp命令直接调用。 

导出的 gulpSaucxs 我们可以直接使用gulp命令来执行。

  1. gulp gulpSaucxs 

输出跟最初是一致的。

导出任务

被gulpfile导出export的任务为公开任务,未被导出的任务会被认为是私有任务。

还是在刚才的代码中,我们新增privateTask方法和导出组合任务。

  1. const gulp = require('gulp'); 
  2. const uglify = require('gulp-uglify'); 
  3. function gulpSaucxs(done) { 
  4.   gulp.src('src/*.js')   // dist与src在共同目录下 
  5.   .pipe(uglify()) 
  6.   .pipe(gulp.dest('dist/js'));   // 相对路径 
  7.   done(); 
  8. // 新增的私有任务 
  9. function privateTask(done) { 
  10.   console.log('hello 「松宝写代码」'
  11. exports.gulpSaucxs = gulpSaucxs;   // gulpSaucxs函数被exports导出是公开任务,可以直接被gulp命令直接调用。 
  12. exports.composeTask = gulp.series(gulpSaucxs, privateTask);  // 导出组合任务 

上面的代码中,privateTask 方法就是没有被直接导出的方法,称为私有任务;gulpSaucxs 方法是被导出的方法,称为公共任务。

私有任务的设计主要是为了内部的使用,通常作为gulp.series()和gulp.paralle()组合的组成部分。

这时候我们执行

  1. gulp composeTask 

执行结果

  1. gulp-test chengxinsong$ gulp composeTask 
  2. [16:14:52] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [16:14:52] Starting 'composeTask'... 
  4. [16:14:52] Starting 'gulpSaucxs'... 
  5. [16:14:52] Finished 'gulpSaucxs' after 8.32 ms 
  6. [16:14:52] Starting 'privateTask'... 
  7. hello 「松宝写代码」 
  8. [16:14:52] Finished 'privateTask' after 1.21 ms 
  9. [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. const gulp = require('gulp'); 
  2. const uglify = require('gulp-uglify'); 
  3. function gulpSaucxs(done) { 
  4.   gulp.src('src/*.js')   // dist与src在共同目录下 
  5.   .pipe(uglify()) 
  6.   .pipe(gulp.dest('dist/js'));   // 相对路径 
  7.   done(); 
  8. // 新增的私有任务 
  9. function privateTask(done) { 
  10.   console.log('hello 「松宝写代码」'); 
  11.   done(); 
  12. exports.gulpSaucxs = gulpSaucxs;   // gulpSaucxs函数被exports导出是公开任务,可以直接被gulp命令直接调用。 
  13. exports.composeTask = gulp.parallel(gulpSaucxs, privateTask);  // 导出组合任务,以最大的并发来运行 

执行

  1. gulp cpmposeTask 

执行结果

  1. chengxinsong$ gulp composeTask 
  2. [18:24:35] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [18:24:35] Starting 'composeTask'... 
  4. [18:24:35] Starting 'gulpSaucxs'... 
  5. [18:24:35] Starting 'privateTask'... 
  6. [18:24:35] Finished 'gulpSaucxs' after 8.24 ms 
  7. hello 「松宝写代码」 
  8. [18:24:35] Finished 'privateTask' after 9.71 ms 
  9. [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. const gulp = require('gulp'); 
  2. const uglify = require('gulp-uglify'); 
  3. function streamTask(done) { 
  4.   return gulp.src('src/*.js'
  5.   .pipe(uglify()) 
  6.   .pipe(gulp.dest('dist/js')); 
  7.   done(); 
  8. exports.streamTask = streamTask; 

输出:dist/js/index.js

2、返回promise

看一个返回promise的例子。

  1. const gulp = require('gulp'); 
  2. function promiseTask(done) { 
  3.   Promise.resolve('返回的值'); 
  4.   done(); 
  5. exports.promiseTask = promiseTask; 

输出:

  1. chengxinsong$ gulp promiseTask 
  2. [19:20:37] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [19:20:37] Starting 'promiseTask'... 
  4. [19:20:37] Finished 'promiseTask' after 1.55 ms 
  5. 返回的值 「松宝写代码」公众号 

3、返回 eventEmitter 事件发射器

看一个返回 eventEmitter 的例子。

  1. // 返回event emitter 
  2. const { EventEmitter } = require('events'); 
  3. function eventEmitterTask(done) { 
  4.   const emitter = new EventEmitter(); 
  5.   setTimeout(() => { 
  6.     emitter.emit('data'
  7.     console.log(emitter, '松宝写代码'
  8.   }, 500); 
  9.   done(); 
  10. exports.eventEmitterTask = eventEmitterTask; 

执行 gulp eventEmitterTask,结果如下:

  1. chengxinsong$ gulp eventEmitterTask 
  2. [21:42:26] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [21:42:26] Starting 'eventEmitterTask'... 
  4. [21:42:26] Finished 'eventEmitterTask' after 1.77 ms 
  5. EventEmitter { 
  6.   _events: [Object: null prototype] {}, 
  7.   _eventsCount: 0, 
  8.   _maxListeners: undefined, 
  9.   [Symbol(kCapture)]: false 
  10. } 松宝写代码 

4、返回 child process 子进程

看一个返回 childProcess 的例子。

  1. // 返回child_process 子进程 
  2. const { exec } = require('child_process'); 
  3. function childProcessTask(done) { 
  4.   exec('data'); 
  5.   console.log('松宝写代码'
  6.   done(); 
  7. exports.childProcessTask = childProcessTask; 

执行 gulp childProcessTask ,结果如下:

  1. chengxinsong$ gulp childProcessTask 
  2. [21:48:32] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [21:48:32] Starting 'childProcessTask'... 
  4. 松宝写代码 
  5. [21:48:32] Finished 'childProcessTask' after 7.02 ms 

5、返回 RxJS observable 观察对象

看一个返回 observable 的例子。

  1. // 返回 observable 观察对象 
  2. const Observable = require('rx').Observable; 
  3. function observableTask(done) { 
  4.   Observable.return('松宝写代码'); 
  5.   console.log('松宝写代码'
  6.   done(); 
  7. exports.observableTask = observableTask; 

执行 gulp observableTask ,结果如下:

  1. chengxinsong$ gulp observableTask 
  2. [21:53:14] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [21:53:14] Starting 'observableTask'... 
  4. 松宝写代码 
  5. [21:53:14] Finished 'observableTask' after 2.28 ms 

6、使用 callback 回调函数

看一个使用 callback 回调函数 的例子。

如果任务(task)不返回任何内容,则必须使用 callback 来指示任务已完成。

如需通过 callback 把任务(task)中的错误告知 gulp,将 Error 作为 callback 的参数。

  1. // 返回 callback 回调函数 
  2. function callbackTask(done) { 
  3.   console.log('松宝写代码'
  4.   done(new Error('抛出错误了')); 
  5. exports.callbackTask = callbackTask; 

执行 gulp callbackTask 结果

  1. chengxinsong$ gulp callbackTask 
  2. [21:58:22] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [21:58:22] Starting 'callbackTask'... 
  4. 松宝写代码 
  5. [21:58:22] 'callbackTask' errored after 2.09 ms 
  6. [21:58:22] Error: 抛出错误了 
  7.     at callbackTask 

7、使用 async/await

看一个使用 async/await 异步函数 的例子。

可以将任务(task)定义为一个 async 函数,它将利用 promise 对你的任务(task)进行包装。这将允许你使用 await 处理 promise,并使用其他同步代码。

  1. // 使用 async/await 回调函数 
  2. const fs = require('fs'); 
  3. async function asyncTask(done) { 
  4.   const { version } = fs.readFileSync('package.json'); 
  5.   console.log(version, 'version====='
  6.   const data = await Promise.resolve('松宝写代码'); 
  7.   console.log(data, '松宝写代码========='
  8.   done(); 
  9. exports.asyncTask = asyncTask; 

执行 gulp asyncTask 结果

  1. chengxinsong$ gulp asyncTask 
  2. [22:26:06] Using gulpfile ~/Desktop/coding/full_stack_knowledge_list/article/gulp/gulp-test/gulpfile.js 
  3. [22:26:06] Starting 'asyncTask'... 
  4. undefined version===== 
  5. 松宝写代码 松宝写代码========= 
  6. [22:26:06] Finished 'asyncTask' after 2.02 ms 

八、我们来看一个实例

比如我们需要

  • 首先清空dist目录,使用series处理
  • 然后 压缩css和压缩js 并行进行处理,使用parallel处理
  • 输出到dist/js和dist/css
  1. // 实例 
  2. const minifycss = require('gulp-minify-css'); //压缩css 
  3. const del = require('del'); // 删除目录 
  4. // 清空目录 
  5. function clean(done) { 
  6.   del(['dist/**']); 
  7.   done(); 
  8. // 压缩css 
  9. function minifyCss(done) { 
  10.   gulp.src('src/*.css'
  11.   .pipe(minifycss()) 
  12.   .pipe(gulp.dest('dist/css')); 
  13.   done() 
  14. // 压缩js 
  15. function uglifyJs(done) { 
  16.   gulp.src('src/*.js'
  17.   .pipe(uglify()) 
  18.   .pipe(gulp.dest('dist/js')); 
  19.   done(); 
  20. exports.exampleGulpTask = gulp.series(clean, gulp.parallel(minifyCss, uglifyJs));   // 执行顺序 clean => 并行执行 css js 压缩 

 

责任编辑:姜华 来源: 松宝写代码
相关推荐

2017-02-13 20:22:42

Android发布项目jcenter

2022-09-28 09:43:35

服务限流

2022-09-28 07:18:34

服务限流部署

2020-03-10 22:01:54

物联网安全物联网IOT

2022-07-11 09:36:38

SpringJava开发

2020-08-17 17:09:01

机器学习技术人工智能

2021-05-10 16:41:19

机器学习人工智能IT

2019-10-10 14:48:19

深度学习人工智能

2009-10-28 10:55:27

2009-10-29 10:48:51

光纤接入技术

2009-10-27 09:35:58

ADSL接入技术

2009-10-30 09:42:39

Internet接入技

2009-10-27 11:34:36

无线接入技术

2009-10-30 10:40:59

2019-12-03 09:31:14

编程语言程序员Python

2020-09-23 07:39:59

SpringBoot项目Redis

2011-07-22 15:56:18

iPhone Interface Builder

2017-04-29 10:16:14

机器学习数据清洗数据整理

2017-05-02 08:40:36

机器学习预处理整理

2009-11-05 13:25:19

接入网方式
点赞
收藏

51CTO技术栈公众号