前言
这篇文章本应该在去年 17 年写的, 但因为种种原因没有写, 其实主要是因为懒(捂脸).gulp 出来的时间已经很早了, 16 年的时候还很流行, 到 17 年就被 webpack
碾压下去了, 不过由于本人接触 gulp 的时候比较晚, 16 年的时候才听说有这么个玩意, 正真用它是在 17 年的时候, 但是虽然现在 webpack 已经大行其道, 我们每个人都
在积极去拥抱它, 不过 gulp 在现在来说也并不是一无是处, 还是有用到的地方, 所以, 这篇文章我觉得还有有必要写的, 就当做是为 gulp 写的最后一篇文章吧 , 做技术就是
这么辛苦, 技术更新太快, 2,3 年的时间就要换一拨技术, 又得学习新的东西, 不然面对这么激烈的市场, 就得被淘汰. 废话不多说了, 下面开始正文.
gulp 是什么, 能做什么
gulp 是一个前端自动化流程构建工具, 诸如, CSS,js, 图片合并压缩, less,sass 编译, 以前我们需要手工才能完成的工作, 现在只要通过 gulp 并结合 gulp 插件就可以轻松的处理这些操作, 极大的节省了开发时间, 优化开发流程, 提供生产效率. 它跟 gruntjs 相比, gulpjs 无需写一大堆繁杂的配置参数, 提供的 API 非常简单, 学习起来也很容易, 另外, gulp 是基于 nodejs, 是通过 stream 流的形式来读取和操作数据, 速度方面更快.
- gulp API
- 1,gulp.src()
输出 (Emits) 符合所提供的匹配模式 (glob) 或者匹配模式的数组 (array of globs) 的文件. 将返回一个 Vinyl files 的 stream 它可以被 piped 到别的插件中.
- gulp.src('client/templates/*.jade')
- .pipe(jade())
- .pipe(minify())
- .pipe(gulp.dest('build/minified_templates'));
- 2,gulp.dest()
能被 pipe 进来, 并且将会写文件. 并且重新输出 (emits) 所有数据, 因此你可以将它 pipe 到多个文件夹. 如果某文件夹不存在, 将会自动创建它.
- gulp.src('./client/templates/*.jade')
- .pipe(jade())
- .pipe(gulp.dest('./build/templates'))
- .pipe(minify())
- .pipe(gulp.dest('./build/minified_templates'));
- 3,gulp.task()
定义一个使用 Orchestrator 实现的任务(task).
- gulp.task('somename', function() {
- // 做一些事
- });
- 4,gulp.watch()
监视文件, 并且可以在文件发生改动时候做一些事情. 它总会返回一个 EventEmitter 来发射(emit) change 事件.
- var watcher = gulp.watch('js/**/*.js', ['uglify','reload']);
- watcher.on('change', function(event) {
- console.log('File' + event.path + 'was' + event.type + ', running tasks...');
- });
整理的一些 gulp 插件
一, 必备插件, 一些基础插件
gulp-htmlmin 看到名字就能知道, 这个插件是用来压缩 HTML.PS: 注释啥的都可以去掉哦, 看文档 get 更多技能哈
gulp-imagemin 除了能压缩常见的图片格式, 还能压缩 SVG, 叼叼的~
gulp-clean-css 压缩 CSS. 我原本推荐的是 gulp-minify-css, 结果其首页中已建议改用 gulp-clean-css...
gulp-uglify 专业压缩 Javascript
gulp-concat 上面几个都是压缩, 这插件是管合并的... 恭喜,"减少网络请求" 的成就达成:)
gulp-autoprefixer 给 CSS 增加前缀. 解决某些 CSS 属性不是标准属性, 有各种浏览器前缀的情况, 灰常有用
gulp-rename 修改文件名称. 比如有时我们需要把 app.js 改成 app.min.js, 瞬间高级了
gulp-util 最基础的工具, 但俺只用来打日志...
二, 常用插件, 一些有用的插件, 但使用场景和频率没那么高的好插件
run-sequence gulp 的 task 都是并行 (异步) 执行, 如果遇见需要串行的场景, 那么这个插件就是必备了. 偶的使用场景是: 处理(压缩, 合并等等) CSS/JS, 再 gulp-rev, 再上传 CDN; 然后使用 CDN 的地址替换 HTML 中的 CSS/JS 地址, 再压缩 HTML. 那么替换 HTML 这步须在之前的工作处理完后再执行. ** 最后要说, gulp4.0 发布后, 不需要 RS 也可以搞定串行任务了 **
del / gulp-clean 删除. 俺的使用场景是: JS/CSS 文件都会在压缩后使用 gulp-rev, 即文件名被 hash, 然后再上传到 CDN, 最后俺再使用 删除插件 把本地压缩后的文件删除掉, 不用多余保存.
gulp-rev 把静态文件名改成 hash 的形式.
gulp-rev-replace 配合 gulp-rev 使用, 拿到生成的 manifest.json 后替换对应的文件名称.
gulp-rev-collector 到线上环境前, 我会用来配合 gulp-rev 使用, 替换 HTML 中的路径
gulp-rev-append 给页面引用的静态文件增加 hash 后缀, 避免被浏览器缓存... 当然, 如果是使用 CDN, 这个套路就不行了
gulp-connect / gulp-livereload LiveReload 的俩款插件都值得拥有, 不过都各稍有学习成本, 看看文档就明白鸟
gulp-sourcemaps 处理 JavaScript 时生成 SourceMap; 如果你不了解 SourceMap, 可以看看这篇阮一峰大神的Source Map 详解
gulp-load-plugins 帮忙偷懒用的, 可以帮我们加载插件, 不用 require 或者 import... 当然, 俺个人感觉用了这个插件后, 阅读 gulpfile.js 的可读性差了, 鱼和熊掌不可兼得:(
gulp-jshint JavaScript 代码校验
gulp-sass / gulp-less 写 CSS 的同学都懂哈
三, 进阶插件, 根据业务场景的不同, 我们可能会用到这些插件
babel JS 语法新特性用起来. 这个插件可以让我们用新的 标准 / 特性 / 提案 写 JavaScript 代码, 然后再向下 转换编译, 最终生成随处可用的 JavaScript 代码. 更通俗的说话就是: 可以用新的规范写代码, 经过 babel 编译后生成没有兼容问题的代码.
gulp-flatten 移动指定文件, 不想压缩或者合并的时候, 直接用这个插件把对应文件移动到指定文件夹. 俺偶尔在内部项目会偷懒用上, 图方便:)
gulp-coffee CoffeeScript 值得去了解
gulp-markdown-pdf 把 Markdown 编译为 PDF
gulp-markdown 写手的福音, 可以把 Markdown 转成 HTML
gulp-html2md 把 HTML 编译为 Markdown
gulp-tinypng 超屌的图片压缩工具, 使用 Tinypng 引擎. PS: 因为 Tinypng 免费帐号有月限制, 所以使用使需注意.
sprity 生成雪碧图. 稍有点学习成本, 仔细阅读文档即可.
gulp-if 可以在 pipe 里面写点逻辑了, 屌不屌. 举例: 比如处理 ./pub/*.js, 如果文件名称是 xxx.js, 那么不处理; 更可以用来区分当前是开发环境还是生产环境.
gulp-file-include 俺搞内部项目的时候会用到, 让 HTML 组件化的第一小步
gulp-git 直接在 Build 时把代码都提交到 git 上了... 特么劳资懒起来连我自己都害怕
gulp-qiniu 用于把指定文件上传至七牛的指定路径下(PS: 首先, 你得有自己的七牛账号和空间)
gulp-notify 在控制台中加入文字描述, build 的时候更高级有木有. 当然, 当需要的时候把错误信息也展示出来会很有帮助. 更高级的功能就需要你查看其文档了~
gulp-plumber gulp 的错误处理有点坑, 假如发生错误进程就挂了. 相对的解决办法不少, 但是这个是我个人比较推荐的, 比特么在容易出错的地方写错误监听靠谱. 所以这个插件可以阻止 gulp 插件发生错误导致进程退出并输出错误日志.
gulp 的使用
1, 在项目根目录下创建一个名为 gulpfile.js 的文件
- var gulp = require('gulp');
- gulp.task('default', function() {
- console.log("执行第一个 gulp 任务")
- });
输入 gulp 命令执行该任务, 不指定任务名称 则默认执行 default 任务
2, 同时执行多个任务
- gulp.task('n1',function(){
- console.log("执行任务 n1")
- });
- gulp.task('n2',function(){
- console.log("执行任务 n2")
- });
- gulp.task('N',['n1','n2']);
3, 如果有 2 个任务存在依赖关系, 如任务 A 依赖任务 B, 在 B 任务执行完成之后再执行 A 任务
- gulp.task('B',function(){
- console.log("执行任务 B")
- });
- gulp.task('A',['B'],function(){
- console.log("任务 B 执行完成之后, 开始执行任务 A")
- });
4, 通过 gulp.watch 监听文件变化, 这里新建一个 watch task 任务, 用 gulp.watch 来监听 index.html 文件, 执行该 task 任务
- gulp.task('watch',function(){
- gulp.watch('./src/index.html').on('change', function(event) {
- console.log('File' + event.path + 'was' + event.type + ', running tasks...');
- });
- });
修改 index.html 文件, 可以看到控制台输出以下内容, event.type 输出的是 changed, 除此之外还有 added, deleted 类型
5, 编译 less
这里使用 gulp-less 插件
安装 npm install --save-dev gulp-less
- var less = require("gulp-less");
- gulp.task('less',function(){
- console.log("开始编译 less...")
- gulp.src('./src/less/index.less')
- .pipe(less())
- .pipe(gulp.dest('./src/css'));
- console.log("less 编译完成");
- });
可以看到自动为我们生成了一个 index 同名 css 文件
使用 gulp-postcss 和 autoprefixer 插件处理浏览器前缀, 解决浏览器兼容性问题, 不必手动添加 css 前缀, 并且支持 soucemap
安装
- npm install gulp-postcss --save-dev
- npm install autoprefixer --save-dev
- npm install gulp-sourcemaps --save-dev
- var less = require("gulp-less");
- var postcss = require('gulp-postcss');
- var sourcemaps = require('gulp-sourcemaps');
- var autoprefixer = require('autoprefixer');
- gulp.task('less',function(){
- console.log("开始编译 less...")
- gulp.src('./src/less/index.less')
- .pipe(less())
- .pipe(sourcemaps.init())
- .pipe(postcss([autoprefixer()]))
- .pipe(sourcemaps.write('.'))
- .pipe(gulp.dest('./src/css'));
- console.log("less 编译完成");
- });
修改 less 文件添加以下样式:
.win{transform: translateX(-50%);}
执行编译 less 任务, 可以看到 index.css 文件自动为 transform 添加了浏览器前缀
同时也为我们生成了一个 map 格式文件
6,watch 监听 less 文件变化, 自动执行 less 编译任务
- gulp.task('watch',function(){
- gulp.watch(['./src/less/index.less'],['less']);
- });
当修改 less 文件并保存时, 看到 less 文件已经编译完成了
7, 使用 broswer-sync 自动刷新浏览器
安装
- npm install browser-sync --save-dev
- // 静态服务器 + 监听 less/html 文件
- var browserSync = require('browser-sync').create();
- gulp.task('browser-sync',['less'],function(){
- browserSync.init({
- server: {
- baseDir: "./src" // 从这个项目的 src 目录启动服务器
- }
- });
- gulp.watch(['./src/less/index.less'],['less']);// 监听 less 文件
- gulp.watch("src/*.html").on('change', browserSync.reload);// 监听 html 文件变化 自动刷新浏览器
- });
最后, 修改 html 文件并保存, 可以看到浏览器自动刷新了
less+css 浏览器注入
在 less 任务后面添加以下代码, 将 less 编译后的 css 注入到浏览器里实现更新, 换句话说就是我们修改 less 文件后编译完成后的 css 反应到浏览器页面中
.pipe(browserSync.reload({stream: true}));
添加以上代码后, 但发现还是无法实现刷新 , 这里如果我们编译 less 使用了 sourcemap, 则无法刷新, 可以通过 gulp-filter 来解决.
安装:
npm install gulp-filter --save-dev
修改编译 less 的任务, 添加红色部分内容即可
8, 使用 gulp-clean-css 压缩 css 文件并重命名
安装:
- npm install gulp-clean-css --save-dev
- npm install gulp-rename --save-dev
- // 压缩 css 文件并重命名
- var cleanCSS = require('gulp-clean-css');
- var rename = require("gulp-rename");
- gulp.task('minify-css',function(){
- gulp.src('./src/css/*.css')
- .pipe(rename({suffix: '.min'})) //suffix 添加后缀 其他的还有 prefix , extname 等
- .pipe(cleanCSS())
- .pipe(gulp.dest('./src/css'));
- });
执行该 task, 可以看到生成了 index.min.css 压缩文件
9, 为我们的 css 文件 MD5 命名 并且在引用的文件路径替换
主要用到 gulp-rev 和 gulp-rev-collector 这两个插件
安装
- npm install gulp-rev --save-dev
- npm install gulp-rev-collector --save-dev
- // 压缩 css 文件并重命名
- // md5 文件命名 引用路径替换
- var cleanCSS = require('gulp-clean-css');
- var rename = require("gulp-rename");
- var rev = require('gulp-rev'); //- 对文件名加 MD5 后缀
- var revCollector = require('gulp-rev-collector'); //- 路径替换
- gulp.task('minify-css',function(){
- console.log('开始压缩 css 文件')
- return gulp.src('./src/css/*.css')
- .pipe(rename({suffix:'.min'})) // 文件重命名 suffix 添加后缀 其他的还有 prefix , extname 等
- .pipe(cleanCSS()) // 压缩处理
- .pipe(rev()) //- 文件名加 MD5 后缀
- .pipe(gulp.dest('./src/css')) //- 输出文件本地
- .pipe(rev.manifest()) //- 生成一个 rev-manifest.json 后面的文件路径替换依据此文件内容
- .pipe(gulp.dest('./rev')); //- 将 rev-manifest.json 保存到 rev 目录内
- console.log('css 压缩完成...')
- });
gulp 运行 minify-css 任务, 可以看到生成了 md5 命名的 css 压缩文件
执行压缩之前先删除文件
del 和 gulp-clean 插件 都是用于清空文件, del 可以用于替代 gulp-clean, 不推荐使用 gulp-clean 了
安装
- npm install del --save-dev
- // clean 任务: 在执行压缩之前先 clean
- var del = require('del');
- gulp.task('clean',function(cb){
- return del(['./dist']);
- })
10, 使用 gulp-sequence 插件处理同步任务
run-sequence gulp 的 task 都是并行 (异步) 执行, 如果遇见需要串行的场景, 那么这个插件就是必备了. 偶的使用场景是: 处理(压缩, 合并等等) CSS/JS, 再 gulp-rev, 再上传 CDN; 然后使用 CDN 的地址替换 HTML 中的 CSS/JS 地址, 再压缩 HTML. 那么替换 HTML 这步须在之前的工作处理完后再执行. ** 最后要说, gulp4.0 发布后, 不需要 RS 也可以搞定串行任务了 **
执行前端代码自动构建, 一般会分为以下几个步骤
1. 清理目标目录(任务: clean)
2. 代码压缩打包, 这其中包括对 JS,CSS,HTML 以及图片的处理(任务: minify:js,minify:css,minify:html,minify:image)
3. 监控(任务: watch)
安装
- npm install --save-dev run-sequence
- // 同步执行任务
- var runSequence = require('run-sequence');
- gulp.task('build', function() {
- runSequence('rev');
- });
11,javascript 代码压缩
gulp-uglify
安装
- npm install gulp-uglify --save-dev
- var uglify = require('gulp-uglify');
- gulp.task('minify-js',function(){
- gulp.src('src/js/*.js')
- .pipe(uglify())
- .pipe(gulp.dest('dist/js'));
- });
压缩之后代码:
12,html 代码压缩
gulp-htmlmin
安装
- npm install gulp-htmlmin --save-dev
- var htmlmin = require('gulp-htmlmin');
- gulp.task('minify-html', function() {
- return gulp.src('src/*.html')
- .pipe(htmlmin({collapseWhitespace: true}))
- .pipe(gulp.dest('dist'));
- });
压缩之后代码:
13, 图片压缩(包括 PNG,JPEG,GIF 和 SVG 图片)
gulp-imagemin
安装
- npm install gulp-imagemin --save-dev
- gulp.task('minify-img', function() {
- return gulp.src('src/images/*.{png,jpg,gif,ico}')
- .pipe(imagemin())
- .pipe(gulp.dest('dist/images'));
- });
压缩之前大小
压缩之后大小
其他参数
- var imagemin = require('gulp-imagemin');
- gulp.task('minify-img', function() {
- return gulp.src('src/images/*.{png,jpg,gif,ico}')
- .pipe(imagemin({
- optimizationLevel: 5, // 类型: Number 默认: 3 取值范围: 0-7(优化等级)
- progressive: true, // 类型: Boolean 默认: false 无损压缩 jpg 图片
- interlaced: true, // 类型: Boolean 默认: false 隔行扫描 gif 进行渲染
- multipass: true // 类型: Boolean 默认: false 多次优化 svg 直到完全优化
- }))
- .pipe(gulp.dest('dist/images'));
- });
14,js 代码合并, 减少 http 请求数量
gulp-concat
安装
- npm install gulp-concat --save-dev
- var concat = require('gulp-concat');
- gulp.task('jsconcat', function () {
- gulp.src('src/js/*.js')
- .pipe(concat('main.js'))// 合并后的文件名
- .pipe(gulp.dest('dist/js'));
- });
坑记录
1, 在编写 less 文件时报以下这个错误, 发现是因为我 sublime 安装了 less2css 这个插件
首选项 -pageage setting 找到 less2css, 发现 default 设置 autocompile 是 true 自动编译
修改 user 设置将 autoCompile 设置为 false 即可
- {
- "autoCompile": true
- }
2, 在压缩 css 文件时, 生成格式有问题
在压缩之前先清空目标文件
3, 关于 gulp 的 gulp-clean-css 压缩插件参数问题
这是告诉 cleancss 压缩时要不要保留 IE8 及以下兼容写法, 写 compatibility:'ie7'就是保留 ie7 兼容写法.. 比如 zoom:1; 这些, 不保留它就给你删除了..
压缩插件不仅仅是压缩, 还能优化, 如果你用 gulp-cssnano, 还能帮你把多余的类名和属性合并.. 等等
4,gulp 中的 return
在 gulp 这里, 返回的是 gulp.src 这个对象, 以便接下来的回调 (如果有的话) 能继续调用这个 gulp.src 对象, 完成其他的事情.
task 的回调函数必须得有返回值
return a promise or event stream. 否则程序就相当于同步的
当任务有返回以上返回值时, 则任务会按一定的顺序执行.
5. 在开启静态服务器模式下, 监听文件变化, 如果执行 clean 删除任务会报以下错误
在开发环境, 静态服务器模式下, 不要执行 clean 任务
6,gulp.watch 监听
- gulp.task('watch',function(){
- gulp.watch('./stylesheets/**/*.scss',['sass']);
- })
以上代码,** 是指所有深度的文件夹, 包括 varible 和 mixin
最后
总结一下, 本文从 gulp 是什么, gulp 能做什么出发, 对 gulp 简单的介绍了一下, 包括 gulp 提供的一些 API, 然后整理并罗列了一些开发中常用到的 gulp 插件,
最后, 就是从 gulp 安装到使用详细介绍了 gulp 的用法, 以及使用 gulp 插件来构建前端自动化的开发流程.
以上在介绍 gulp 的使用时, 我也准备了一个 gulp 的 demo https://github.com/fozero/frontcode/tree/master/gulp-demo ,demo 代码我已经上传到 github 中, 大家可以自行下载. 另外, 我建立了一个 gulp 自动化构建工程模板, 支持 less 编译, html,css,js 文件及图片压缩, 自动添加浏览器前缀, 本地开发环境下文件监听浏览器自动刷新等, 不需要再重新搭建 gulp 工程, 就可以轻松构建你的前端 gulp 自动化工作流程, 代码已上传到 github, 地址 https://github.com/fozero/template-gulp , 如果喜欢的话, 欢迎 star 哦~ , 如有问题也可以在上面提 issues
相关资料
- https://www.gulpjs.com.cn/
- https://www.cnblogs.com/2050/p/4198792.html
- https://www.cnblogs.com/Darren_code/p/gulp.html
- https://www.cnblogs.com/2050/p/4198792.html
- https://blog.csdn.net/mjzhang1993/article/details/68485085
作者: fozero
来源: https://www.cnblogs.com/fozero/p/8994464.html