Gulp的基本使用

1、yarn init 初始化 package.json

2、yarn add gulp --dev 将gulp作为开发依赖安装

3、项目根目录创建gulpfile.js,作为gulp的入口文件

//gulp 的入口文件
exports.foo = () => {console.log("foo task working!")
}

4、命令行通过yarn gulp foo运行这个任务

最新的gulp当中取消了同步代码模式,约定了每个任务都是异步的,每个任务结束需要调用回调函数或者其他方式来标记任务已完成

exports.foo = done => {console.log("foo task working!")done() //标识任务完成
}


5、如果任务名称为default,会作为gulp的默认任务出现

exports.foo = done => {console.log("foo task working!")done() //标识任务完成
}
exports.default = done => {console.log("default task working!")done()
}

执行命令时不填任务名称,会默认执行default任务

6、gulp4.0以前注册任务需要通过gulp模块里的task方法去实现

const gulp = require('gulp')
gulp.task('bar', done => {console.log("bar task working!")done()
})


虽然该方法仍然可以使用,但是不被推荐,更推荐使用导出函数成员的方式

Gulp的组合任务

const { series, parallel } = require('gulp')const task1 = done => {setTimeout(() => {console.log("task1 working")done()}, 1000);
}
const task2 = done => {setTimeout(() => {console.log("task2 working")done()}, 1000);
}
const task3 = done => {setTimeout(() => {console.log("task3 working")done()}, 1000);
}exports.foo = series(task1, task2, task3) //串行任务
exports.bar = parallel(task1, task2, task3)    //并行任务// parallel:创建一个并行的构建任务,可并行执行多个构建任务 parallel(‘任务1’,‘任务2’,‘任务3’,…)
// series:创建一个串行的构建任务,会按照顺序依次执行多个任务 series(‘任务1’,‘任务2’,‘任务3’,…)


Gulp的异步任务

1、回调函数方式(done)

exports.callback = done=>{console.log("callback task")done()
}
exports.callback_error = done=>{console.log("callback_error task")done(new Error('task failed!'))
}

错误优先,多个任务同时执行时,后面的任务不会执行

2、promise方式

exports.promise = () => {console.log("promise task")return Promise.resolve()
}
exports.promise_error = () => {console.log("promise_error task")return Promise.reject(new Error('task failed'))
}

3、async await方式(node环境8以上的可以使用)

const timeout = time => {return new Promise(resolve => {setTimeout(resolve, time)})
}
exports.async = async () => {await timeout(1000)console.log("async task")
}

4、stream方式(最常见,因为构建系统大都是在处理文件)

const fs = require('fs')
exports.stream = () => {const readStream = fs.createReadStream('package.json')const writeStream = fs.createWriteStream('temp.txt')readStream.pipe(writeStream)return readStream
}
//结束的时机就是当readStream end的时候,文件读取完成会触发end事件,gulp就知道任务已经完成
const fs = require('fs')
exports.stream = done => {const readStream = fs.createReadStream('package.json')const writeStream = fs.createWriteStream('temp.txt')readStream.pipe(writeStream)//用done模拟结束任务readStream.on('end', () => {done()})
}

Gulp构建过程核心工作原理

//gulp 常规核心工作过程
const fs = require('fs')
const { Transform } = require('stream')
exports.default = () => {//文件读取流const read = fs.createReadStream('normalize.css')//文件写入流const write = fs.createWriteStream('normalize.min.css')//文件转换流const transform = new Transform({transform: (chunk, encoding, callback) => {//核心转换过程实现//chunk => 读取流中读取到的内容 (Buffer) toString拿到文本内容const input = chunk.toString()//去掉空白字符及css注释const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '')//callback是错误优先的回调函数,第一个参数应该传错误对象,没有则传nullcallback(null, output)}})read.pipe(transform) //转换.pipe(write) //写入 return read
}

Gulp文件操作api

const { src, dest } = require('gulp')
const cleanCss = require('gulp-clean-css')
const rename = require('gulp-rename')
exports.default = () => {//文件读取流const read = src("src/*.css")//文件写入流const write = dest('dist')read.pipe(cleanCss()).pipe(rename({extname:'.min.css'})).pipe(write) //写入 return read
}// src:创建读取流,可直接src(‘源文件路径’) 来读取文件流
// dest:创建写入流,可直接dest(‘目标文件路径’) 来将文件流写入目标文件中
// gulp-clean-css插件用于压缩css代码
// gulp-rename插件用于文件重命名

Gulp自动化构建案例

这是项目的基本目录结构,assets主要用于存放样式文件,脚本文件,图片,字体等

最终的构建目标是

  1. 将html文件转化为html文件,存放到dist下,并且处理html中得一些模板解析,以及资源文件得引入问题(如html文件中引入了css,js 等)。并对html文件进行压缩处理
  2. 将scss文件转化为浏览器可识别得css文件,并压缩
  3. 将js文件转化为js文件,并处理js代码中一些浏览器无法识别得语法转化为可识别得。如ES6.ES7转ES5
  4. 将图片和字体进行压缩
  5. 实现一个开发服务器,实现边开发,边构建
  6. 构建完成后优化

样式编译

yarn add gulp-sass --dev
yarn add sass --dev
const sass = require('gulp-sass')(require('sass'))
const style = () => {return src('src/assets/styles/*.scss', { base: 'src' }).pipe(sass({ outputStyle: 'expanded' })).pipe(dest('dist'))
}

提示:在我们每次构建完一个任务可以通过module.exports将任务名暴露出去,然后运行命令行yarn gulp "任务名"(例如:yarn gulp style)来确保我们当前写完的任务是没有问题的,然后再进行其他任务的构建

  • 安装样式插件gulp-sass时,可能里面的node-sass下载不下来导致运行时报错,要另外安装sass
  • src第二个参数可以传一个{ base: 'src' }选项参数,用于指定基准路径,会保留src后面的文件目录
  • sass模块工作时,会把下划线 “_” 开头的文件当做主文件依赖的文件,因此不会被转换,会被忽略掉
  • sass模块工作生成的样式代码中,css结束的括号可能默认是跟在最后的属性后面,可以通过指定选项outputStyle: 'expanded'将括号换行

脚本编译

1、只安装gulp-babel模块运行可能会报错,因为gulp-babel这个插件只是帮助唤起@babel/core,真正执行转换的模块是@babel/core,同时还需要安装@babel/preset-env这个模块,用于转换ES6的一些新特性

yarn add gulp-babel --dev
yarn add @babel/core @babel/preset-env --dev

2、同时要在babel方法里面添加presets的配置

const babel = require('gulp-babel')
const script = () => {return src('src/assets/scripts/*.js', { base: 'src' }).pipe(babel({presets:['@babel/preset-env']})).pipe(dest('dist'))
}

如果忘记添加presets:['@babel/preset-env'],可能会导致转换没有效果

原因:babel只是ECMAScript的转换平台,只是提供一个环境,具体实现转换的是babel里面的插件

模板编译

yarn add gulp-swig --dev
const swig = require('gulp-swig')
const page = () => {return src('src/*.html', { base: 'src' }).pipe(swig({ data: data })).pipe(dest('dist'))
}
  • 读取文件时,如果不只是转换src下面的html文件,同时有些子目录下面的html也需要转换,路径匹配规则要写成src('src/**/*.html'),表示src下面任意子目录下的html文件
  • 可以通过swig({data:myData})将数据传递到页面模板上

图片和字体文件转换

yarn add gulp-imagemin --dev
const imagemin = require('gulp-imagemin')
const image = () => {return src('src/assets/images/**', { base: 'src' }).pipe(imagemin()).pipe(dest('dist'))
}
const font = () => {return src('src/assets/fonts/**', { base: 'src' }).pipe(imagemin()).pipe(dest('dist'))
}

其他文件及文件清除

yarn add del --dev   //安装 del 模块
const del = require('del')
const extra = () => {return src('public/**', { base: 'public' }).pipe(dest('dist'))
}
const clean = () => {return del(['dist'])
}

自动加载插件

使用gulp-load-plugins后,无需在gulpfile.js使用require关键字一个一个的把依赖包导入进去 ,使用到的插件要在package.json里面找到对应的依赖,否则可能报错

yarn add gulp-load-plugins --dev
const loadPlugins = require('gulp-load-plugins')
const plugins = loadPlugins()

所有使用的gulp插件都会成为plugins的属性,命名方式就是'gulp-'后面的名称,如果插件名有'-'拼接,则改为驼峰,例如:plugins.babelplugins.imageminplugins.swig等等

默认配置项(知识拓展)官方文档:https://www.npmjs.com/package/gulp-load-plugins

gulpLoadPlugins({DEBUG: false, // 设置为true时,该插件会将信息记录到控制台。 对于错误报告和问题调试很有用pattern: ['gulp-*', 'gulp.*', '@*/gulp{-,.}*'], // 将会去搜索的数据overridePattern: true, // 如果为true,则覆盖内置模式。 否则,扩展内置模式匹配器列表。config: 'package.json', // 定义从哪里搜索插件scope: ['dependencies', 'devDependencies', 'peerDependencies'], //在被搜索的文件中要去查看哪些键值replaceString: /^gulp(-|\.)/, // 将模块添加到上下文时要从模块名称中删除的内容,例如gulp-rename在使用是为$.rename()即可,无需前缀camelize: true, //如果为true,则将带连字符的插件名称转换为驼峰式lazy: true, // 插件是否应按需延迟加载rename: {}, //重命名插件的映射renameFn: function (name) { ... }, //处理插件重命名的功能(默认有效)postRequireTransforms: {}, // see documentation belowmaintainScope: true // 切换加载所有npm范围,如非作用域包
});

开发服务器

可以结合其他任务实现自动编译,自动刷新浏览器页面,大大提高开发效率

yarn add browser-sync --dev
const browserSync = require('browser-sync')
const bs = browserSync.create()
const serve = () => {bs.init({notify: false,          //设置每次启动预览时右上角的提示是否显示port: 2080,             //端口 默认3000open:true,              //启动时自动打开浏览器,默认truefiles:'dist/**',        //启动后监听的文件server: {baseDir: 'dist',    //网站的根目录routes: {           //routes 优先于 baseDir,即请求发生以后,会先看 routes 里面有没有,否则走 baseDir 下面的目录'/node_modules': 'node_modules'}}})
}

监视页面变化

const { watch } = require('gulp')
const serve = () => {watch('src/assets/styles/*.scss', style)watch('src/assets/scripts/*.js', script)watch('src/*.html', page)watch('src/assets/images/**', image)watch('src/assets/fonts/**', font)watch('public/**', extra)bs.init({//......})
}

监听到里面的文件修改之后,就会执行相应的任务,任务一旦触发就会把dist文件覆盖掉,同时brower-sync监听到dist变化,自动同步到浏览器

注意:这里可能会因为swig模板引擎缓存的机制导致页面不会变化,此时需要额外将swig选项中的cache设置为false

构建优化

const serve = () => {watch('src/assets/styles/*.scss', style)watch('src/assets/scripts/*.js', script)watch('src/*.html', page)// watch('src/assets/images/**', image)// watch('src/assets/fonts/**', font)// watch('public/**', extra)// 图片、字体、public文件开发阶段不参与构建,可以提高开发阶段的工作效率// 让图片、字体、public文件变化后可以更新浏览器,浏览器就会重新发起资源请求,就可以拿到变化后的文件watch(['src/assets/images/**','src/assets/fonts/**','public/**'], bs.reload)bs.init({notify: false,port: 2080,open: true,files: 'dist/**', // 这里也可以不使用files监听,可以在上面的每个watch监听执行的对应任务里面加上一个pipe(bs.reload({stream:true})),表示以流的方式往浏览器推入,这种方式更加常见server: {baseDir: ['dist', 'src', 'public'], // 当请求过来,找不到图片字体文件时,会依次向后找,找到源文件routes: {'/node_modules': 'node_modules'}}})
}const compile = parallel(style, script, page)
// build 上线之前执行的任务
// image、font任务可以从compile任务移出,因为开发阶段可以不需要构建,放到build任务
const build = series(clean, parallel(compile, image, font, extra))
const develop = series(compile, serve)
// 这样develop任务就可以在开发阶段以最小的代价把项目构建起来

useref 文件引用处理

yarn add gulp-useref --dev
// 必须要dist生成以后 执行useref
const useref = () => {return src('dist/*.html', { base: 'dist' }).pipe(plugins.useref({ searchPath: ['dist', '.'] })).pipe(dest('dist'))
}

处理引用文件的合并,首先要先找到这些文件,可以添加选项参数{searchPath:['dist', '.']}用来指定从哪些文件路径查找,这里指定dist和根目录

文件压缩

yarn add gulp-htmlmin gulp-uglify gulp-clean-css --dev
// 安装压缩html、js、css的插件

由于需要判断引用的文件类型,来使用对应的插件对其进行压缩,这里还需要用到gulp-if插件

yarn add gulp-if --dev
const useref = () => {return src('dist/*.html', { base: 'dist' }).pipe(plugins.useref({ searchPath: ['dist', '.'] }))// 判断引用的文件的类型 html/css/js.pipe(plugins.if(/\.js$/, plugins.uglify())).pipe(plugins.if(/\.css$/, plugins.cleanCss())).pipe(plugins.if(/\.html$/, plugins.htmlmin({collapseWhitespace: true,minifyCSS: true,minifyJS: true}))).pipe(dest('release'))
}

plugins.htmlmin()默认只是去除属性里面的空白字符,可根据自己的项目需求自定义添加选项参数

  • collapseWhitespace:折叠所有的空白字符和换行符
  • minifyCSS:压缩html文件里style标签内的css代码
  • minifyJS:压缩html文件里script标签内的js代码

重新规划构建过程

由于构建过程中需要userefhtml中的引用文件进行编译压缩处理,所以中间需要有一个临时目录temp用于存放已编译但是还没有开始被useref处理的文件

执行的大概过程:

  1. 所有文件同时进行编译
  2. 样式、脚本、模板编译完成会将编译后的文件写入至临时文件temp,其他的资源文件编译完直接写入最终目录dist
  3. 临时文件生成完以后,useref会对编译后文件内的引用文件进行合并和压缩处理,处理完成写入最终目录dist

补充

1、最终需要将外部需要执行的任务暴露出去,同时可以将暴露出去的任务定义到package.jsonscripts当中,更容易让人理解

"scripts": {"clean": "gulp clean","build": "gulp build","develop":"gulp develop"
},
//设置过后可以直接通过 yarn develop 来启动项目

2、.gitignore文件中添加忽略文件disttemp

如何使用Gulp完成项目的自动化构建相关推荐

  1. 6个 C 语言项目的自动化构建和测试工具。(文末有位小可爱)

    答案见文末. 今天给大家推荐6个桃子C 语言项目的自动化构建和测试工具,这6个工具都是非常甜蜜实用的,超市里面找不到的.另外今天我们的文末有一位小可爱想请教大家一个问题,希望大家帮帮她. 上期入口:3 ...

  2. Android项目jenkins自动化构建之360加固(一)

    Android项目jenkins自动化构建之360加固(一) 最近Jenkins接手一个项目,项目自动化构建都是在jenkins上做的,包括打包构建--360加固--apk签名--邮件发送apk 总共 ...

  3. express搭建项目--express自动化构建工具

    express自动化构建工具 一.   安装express-generator 全局安装express自动化构建工具 npm install -g express-generator 使用expres ...

  4. 开发脚手架及封装自动化构建工作流

    前端工程化 概述 1.多人协作开发,无法硬性统一大家的代码风格 从仓库中pull回来的代码质量无法保证 2.部分功能开发时需要等待后端服务接口提前完成 3.传统语言或语法的弊端 4.无法使用模块化/组 ...

  5. 自动化构建工具Grunt、Gulp

    使用grunt完成项目的自动化构建 一.准备工作 grunt快要退出历史舞台了,简单学习下 mkdir my-grunt yarn init --yes //创建package模块 yarn add ...

  6. Linux项目自动化构建工具 make/Makefile

    在我们日常写代码中,一个工程的源文件不计其数, 按照类型.功能.模块等分别放在若干个目录中,这时候我们就可以利用makefile来指定哪些文件先编译,哪些后编译,以及更复杂的操作.我们只需要在make ...

  7. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)...

    本文你将学到什么? 本文将以原理+实战的方式,首先对"微服务"相关的概念进行知识点扫盲,然后开始手把手教你搭建这一整套的微服务系统. 项目完整源码下载 https://github ...

  8. Bamboo项目自动化构建

    Bamboo项目自动化构建 本文说明如何使用Bamboo实现Java项目的自动化构建.实现的功能是:能够轮询检测所连接的代码仓库,当检测到源代码更新时,使用Gradle自动进行项目构建,构建完成后可以 ...

  9. 手把手0基础项目实战(一)——教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)......

    手把手0基础项目实战(一)--教你搭建一套可自动化构建的微服务框架(SpringBoot+Dubbo+Docker+Jenkins)... 原文: 手把手0基础项目实战(一)--教你搭建一套可自动化构 ...

最新文章

  1. 进阶第四课 Python模块之os
  2. 分布式大数据sql查询引擎Presto初识
  3. 获取当前日期0点及23点59的时间戳
  4. 程序员的进阶课-架构师之路(12)-2-3-4树
  5. 网络通信 public ip 和 private ip
  6. js中DOM, DOCUMENT, BOM, WINDOW 区别
  7. 系统板I/O端口地址分配(一)
  8. 2013年7月底至8月初51Aspx源码发布详情
  9. 来客电商之微信小程序怎么取名字
  10. 测绘——利用ExifTool提取照片exif信息【windows环境下】(信息非常全)
  11. 博世中国的战略与战术,如何应对复杂多变的中国市场需求
  12. 使用Vuforia创建神奇宝贝GO风格增强现实游戏
  13. 转载:微软内部职位分类和待遇
  14. 关于生产环境跨域问题
  15. C#读IC卡程序 Mwic_32.dll
  16. 专访李开复:人类已打开潘多拉盒子,封堵AI变革只会徒劳
  17. MySQL数据库基础操作(一)
  18. c语言比率分布 函数 rate(m),R语言中统计分布和模拟_R语言培训
  19. pycharm报错SyntaxError: Non-UTF-8 code starting with ‘\xdf‘ in file的一种可能的解决方式
  20. linux性能分析 -- top

热门文章

  1. Laravel Carbon
  2. 华东师范计算机学硕839,华东师范大学-839-2015-计算机考研-真题.pdf
  3. UBER、RBER和MTBF的概念
  4. web前端大作业--响应式风景旅游网页设计(国庆旅游主题-HTML+CSS+JavaScript)实现
  5. DEDE采集规则(很实用)
  6. mvc5 ef mysql_ASP.NET MVC快速入门之数据库操作(MVC5+EF6)[第一篇][上] | Rickytsang洛水寒...
  7. python输入名字输出你好代码_003-输入和输出
  8. 在微信小程序中编写金额摇奖效果
  9. 教授、研究员、高级工程师、工程师,各系列职称体系对比
  10. 应用内版本更新库UpdateVersion