好用的自动化构建工具-gulp

@文章来源:拉钩大前端就业训练营-念念

Gulp

简介

自动化构建工具

自动化构建工具,可以帮我们又快又好的完成自动化构建任务。相比有 npm scripts,自动化构建工具,功能更为强大。更简单易学。其中比较流行的有三款:

  • Grunt

    是第一款自动化构建工具,对前端工程化的发展具有里程碑意义,其生态完善。但是,它的构建是基于临时文件的,所以构建速度较慢,现在用的人越来越少了。

  • Gulp

    Gulp 的构建是基于内存实现的,其构建速度比 Grunt 快,而且,Gulp 的生态也很完善,插件质量很高。目前最为流行。

  • FIS

    FIS 是百度的前端团队对出的,最开始只在百度内部使用。开源后,逐渐在国内流行起来。但是其更新跟不上,最近的更新都是三年前的,而且其生态主要有国人维护( Grunt 和 Gulp 生态是世界范围的 )。所以,其流行度比不上 Gulp。

Gulp

Gulp 是基于 的自动化构建系统。

Gulp 的特点

  • 任务化

    • 所有的构建操作,在 gulp 中都称之为任务
  • 基于流

    • gulp 中所有的文件操作,都是基于 方式进行 ( Gulp有一个自己的内存,通过指定 API 将源文件流到内存中,完成相应的操作后再通过相应的 API 流出去)

基础

使用 Gulp 之前,先在全局安装 gulp-cli ( Gulp 的命令行工具 )

# 全局安装 gulp 客户端
npm i -g gulp-cli 

# 验证安装是否成功
gulp -v

官网:https://gulpjs.com/

基本用法

Gulp 使用的基本逻辑是:先声明任务,再从命令行中执行任务;具体步骤如下:

  1. 使用 Gulp 之前,先在全局安装 gulp-cli

    # 安装 gulp 命令行工具
    npm i -g gulp-cli 
    
    # 验证安装是否成功
    gulp -v
    
  2. 初始化项目

    # 创建项目目录
    mkdir project-name
    
    # 进入项目目录
    cd project-name
    
    # 初始化项目
    npm init --yes
    
  3. 安装 Gulp 包

    # 安装 gulp 包,作为开发时依赖项
    npm i gulp -D
    
  4. 创建 gulpfile 文件

    gulpfile 文件是项目根目录下的 gulpfile.js在运行 gulp 命令时会被自动加载。在这个文件中,你经常会看到类似 src()dest()series()parallel() 函数之类的 Gulp API,除此之外,纯 JavaScript 代码或 Node.js 模块也会被使用。任何导出( exports )的函数都将注册到 Gulp 的任务(task)系统中。

    # 创建任务,任务结束后,需要通过回调函数去标记
    exports.foo = () => {
      console.log('foo task is running')
    }
    

    报错:

    The following tasks did not complete: task
    Did you forget to signal async completion?

    解释:在最新的 Gulp 中,取消了同步代码模式。约定每个任务都必须是一个异步任务

    解决:再函数参数中,设定回调函数(回调函数是异步操作)

  5. 在 gulpfile.js 中注册 Gulp 任务

    # 创建任务,并导出任务
    exports.foo = cb => {
      console.log('foo task is running')
        
      cb()
    }
    
    # 旧版 Gulp 注册任务的语法(无需执行导出操作)
    gulp.task('foo', function(cb) {
      console.log('foo task is running')
        
      cb()
    });
    
  6. 运行 Gulp 任务

    # 运行 foo 任务
    # 如需运行多个任务(task),可以执行 gulp <task> <othertask>
    gulp foo
    
  7. 创建默认任务

    # 默认任务的名称是 default
    exports.default = cb => {
        console.log('default task is running')
        
        cb()
    }
    
    # 运行默认任务, gulp 后无需指定任务名称
    gulp # 效果等同于 gulp default
    

组合任务

Gulp 提供了两个强大的组合方法: series()parallel()

如果需要让任务(task)按顺序执行,请使用 series() 方法(相当于 npm scripts 中的 && )。

如果希望任务(tasks)并行执行,可以使用 parallel() 方法将它们组合起来(相当于 npm scripts 中的 & )。

const gulp = require('gulp')

const task1 = cb => {
  setTimeout(() => {
    console.log('Task 1 is running')
    cb()
  }, 1000)
}

const task2 = cb => {
  setTimeout(() => {
    console.log('Task 2 is running')
    cb()
  }, 1000)
}

const task3 = cb => {
  setTimeout(() => {
    console.log('Task 3 is running')
    cb()
  }, 1000)
}

# 串行方式执行任务,先执行task1, 然后执行task2, 然后执行task3
exports.foo = gulp.series(task1, task2, task3)

# 并行方式执行任务,同时执行task1,task2,task3
exports.bar = gulp.parallel(task1, task2, task3)

# 执行命令
gulp foo # 串行执行
gulp bar # 并行执行

series()parallel() 可以被嵌套到任意深度。通过这两个函数,构建任务可以被任意排列组合,从而满足各种复杂的构建需求。

文件操作

gulp 暴露了 src()dest() 方法用于处理计算机上存放的文件。在代码构建过程中,需要将源文件,写入到目标目录。

# 通过 解构 的方式引入 gulp 中的函数
const { src, dest } = require('gulp')

exports.default = () => {
  // 文件操作
  // 将 src/styles 目录下的 main.css 文件,复制到 dist/styles 目录下
  return src('src/styles/main.less', { base: 'src' }).pipe(dest('dist'))
}

# 执行命令
gulp default
# 或直接执行
gulp

案例演示

样式文件构建

对样式文件进行转换、压缩、重命名。

# 安装相关的 Gulp 插件
npm i gulp-less -D
npm i gulp-autoprefixer -D
npm i gulp-clean-css -D
npm i gulp-rename -D

# 在 gulpfile.js 中添加样式编译内容
const gulp = require('gulp')
const less = require('gulp-less')
// 给 CSS 属性添加前缀的插件(详情请看下方 CSS Hack)
const autoprefixer = require('gulp-autoprefixer')
// 压缩 CSS 的插件
const cleanCss = require('gulp-clean-css')
// 重命名转换文件的插件
const rename = require('gulp-rename')

const style = () => {
  return src('src/styles/*.less', { base: 'src' })
    .pipe(less())
    .pipe(autoprefixer())
    .pipe(cleanCss())
    .pipe(rename({extname: '.min.css'}))
    .pipe(dest('dist'))
}

module.exports = {
  style
}

# 运行命令
npm gulp style

通过样式文件的构建,我们可以更清晰的理解文件操作。

CSS Hack

由于不同浏览器中的渲染引擎不同,这导致了同一段 CSS 代码,在不同的浏览器上解析效果不同(即 CSS 代码具有兼容性问题)。

针对不同浏览器,写不同 CSS 代码的过程称为 CSS Hack

CSS Hack 有三种形式:CSS 属性 Hack、CSS选择符 Hack 和 IE条件注释 Hack( Hack主要针对IE浏览器 )

  • 属性级 Hack

    比如 IE6 能识别下划线“_”和星号“*”,IE7 能识别星号“*”,但不能识别下划线”_

  • 选择符级 Hack

    IE6 能识别 *html .class{}

    IE7 能识别 *+html .class{} 或者 *:first-child+html .class{}

  • IE 条件注释 Hack:

    # 针对 IE6 及以下版本:
    <!--[if lt IE 6]>您的代码<![endif]-->
    

    这类 Hack 不仅对 CSS 生效,对写在判断语句里面的所有代码都会生效。

本小节,只讨论属性级 Hack

不同浏览器的 CSS 属性前缀:

例如:use-select 存在兼容性问题。CSS 属性 Hack 的解决方案如下:

上述添加 CSS 属性前缀的操作,之前是通过程序员手动添加的。这类重复性操作,我们可以通过插件完成。

在 Gulp 中 gulp-autoprefixer 插件,可以根据 caniuse.com 上提供的 CSS 兼容性数据,自动地给 CSS 属性加前缀,以保证 CSS 代码的兼容性问题。

脚本文件构建

对 JS 代码进行 Babel 转换和压缩。

注意:因为不同 babel 版本对应的 gulp-babel 的安装命令不同,所以安装 gulp-babel 之前需要先确定本地 babel 版本 (通过 babel --version 查看)

# Babel 7
$ npm install --save-dev gulp-babel @babel/core @babel/preset-env

# Babel 6
$ npm install --save-dev gulp-babel@7 babel-core babel-preset-env
# 我本地的 babel 版本是 6,所以,执行 6 的安装命令
npm install --save-dev gulp-babel@7 babel-core babel-preset-env

# 安装压缩脚本的插件
npm i gulp-uglify -D

# 在 gulpfile.js 中添加脚本编译内容
const rename = require('gulp-rename')
const babel = require('gulp-babel')
const uglify = require('gulp-uglify')

const script = () => {
  return src('src/scripts/*.js', { base: 'src' })
    .pipe(babel({
      presets: [ 'babel-preset-env' ] // 不同版本的 babel,其转换规则写法也不同
    }))
    .pipe(uglify())
    .pipe(rename({ "extname": ".min.js" }))
    .pipe(dest('dist'))
}

module.exports = {
  style,
  script
}

# 运行命令
gulp script

页面模板构建

对 html 文件的构建,主要指压缩 html 文件。其中 gulp-htmlmin 插件可以完成压缩任务。

gulp-htmlmin 插件的解析器是:https://github.com/kangax/html-minifier

想要查看 htmlmin 的使用参数,可以查看上述链接。

# 添加 htmlmin 插件
npm i gulp-htmlmin -D

# 在 gulpfile.js 中添加页面处理内容
const htmlmin = require('gulp-htmlmin')

const html = () => {
  return src('src/*.html', { base: 'src' })
    .pipe(htmlmin({
      collapseWhitespace: true, // 去除标签之间多余的空行和空白
      minifyCSS: true, // 压缩HTML中的CSS代码
      minifyJS: true // 压缩HTML中的JS代码
    }))
    .pipe(dest('temp'))
}

module.exports = {
  style,
  script,
  html
}

# 运行命令
gulp html

完成上述三个构建任务后,我们可以将 style,script 和 html 任务组合起来。因为 style,script 和 html 之间没有明确的前后顺序,所以,可以进行并行执行,并行执行可以提升构建效率。

# 引入 parallel 函数
const { src, dest, parallel } = require('gulp')

// 任务的并行执行
const build = parallel(style, script, html)

module.exports = {
  build
}

# 运行命令
gulp build

图片(字体)文件转换

对图片文件的构建,主要是指图片的压缩。通过 gulp-imagemin 插件可以完成图片的压缩任务。

# 安装 imagemin 插件
npm i gulp-imagemin -D

# 在 gulpfile.js 中引入图片压缩插件
const imagemin = require('gulp-imagemin')

// 图片构建任务
const image = () => {
  return src('src/images/**', { base: 'src' })
    .pipe(imagemin())
    .pipe(dest('dist'))
}

// 图片构建任务,也可以与以上三个任务一起,并行执行
const build = parallel(style, script, html, image)

module.exports = {
  image,
  build
}

# 运行命令
gulp build

报错处理:

gulp-imagemin: Couldn't load default plugin "gifsicle"

gulp-imagemin: Couldn't load default plugin "optipng"

原因:npm 安装依赖失败

解决:

  1. 配置 hosts (详情参考本节最后的附录部分)
  2. 重新安装 npm i gulp-imagemin -D

文件清除

有时候,我们需要删除一些构建的历史文件,然后再重新构建。删除文件操作,可以通过 del 插件完成。

# 通过del插件来删除指定文件
npm i del -D

const del = require('del')

// 声明清除任务
const clean = () => {
  return del(['dist'])
}

// 编译之前,先执行clean,删除历史文件
const build = parallel(style, script, html, image)
const dev = series(clean, build)

module.exports = {
  clean,
  dev
}

# 运行命令,查看文件是否删除
gulp clean
# 或者
gulp dev

开发服务器

通过web服务器插件,将 dist 下的代码,发布到浏览器查看效果。发布web服务的插件有很多。这里,我们推荐功能强大的 browser-sync。

<img src="C:\Users\changtaoliu\AppData\Roaming\Typora\typora-user-images\image-20201026115412063.png" alt="image-20201026115412063" style="zoom:67%;" />

# 安装 browser-sync 插件
npm i browser-sync -D

# 在 gulpfile.js 中添加开发服务器的内容
const browserSync = require('browser-sync')
const bs = browserSync.create()

// 声明 web 服务构建任务
const serve = () => {
  bs.init({
    server: {
      baseDir: './dist' // 指定服务启动的目录
      routes: {
        '/node_modules': 'node_modules' // 引入 Bootstrap 是设置路径映射
      }
    }
  })
}

module.exports = {
  clean,
  build,
  serve
}

# 运行命令,然后在浏览器查看效果
gulp serve

服务发布成功后,之前学习的内容,也可以拿过来使用,例如:Bootstrap

  1. 下载插件

    # 因为 Bootstrap 和 jQuery 上线之后还要使用,所以,采用 -S 参数(上线依赖)
    npm i bootstrap@3.4.1 jquery -S
    
  2. 引入文件

    Bootstrap 和 jQuery 下载后,文件位于当前目录的 node_modules 下

    # 在 HTML 中引入
    <link rel="stylesheet" href="/node_modules/bootstrap/dist/css/bootstrap.min.css">
    ......
    <script src="/node_modules/jquery/dist/jquery.min.js"></script>
    <script src="/node_modules/bootstrap/dist/js/bootstrap.min.js"></script>
    

    引入路径,需要在 browser-sync 中,通过 routes 参数映射后,才能正确引入(详情查看上述代码)

  3. 使用 Bootstrap

    之前学习的 Bootstrap 的代码,都可以在当前代码中使用。

监视变化(热更新)

监视 src 下文件变化的页面更新,代码一旦更新,浏览器上的页面效果也随之更新。

此时,我们需要监视两个目录的变化,一个是 dist 目录,一个是 src 目录。

<img src="C:\Users\changtaoliu\AppData\Roaming\Typora\typora-user-images\image-20201026115302892.png" alt="image-20201026115302892" style="zoom:67%;" />

  • 监视 dist 目录下代码的变化

    # 通过 browser-sync 中的 files 字段
    files: 'dist/**'
    
  • 监视 src 目录下代码的变化

    # 通过 gulp 中的 watch 函数
    watch(被监视的文件,对应的任务)
    

最终的代码如下:

# 在 gulpfile.js 中添加监视文件变化的代码
const serve = () => {
  // watch(被监视的文件,对应的任务)
  watch('src/index.html', html)
  watch('src/styles/*.less', style)
  watch('src/js/*.js', script)
  watch('src/images/**', image)

  // 初始化服务
  bs.init({
    notify: false,      // 禁用浏览器右上角的 browserSync connected 提示框
    files: 'dist/**',   // 监视 dist 下 文件的变化,然后在浏览器上实时更新
    server: {
      baseDir: './dist', // 指定服务启动的目录
      routes: {
        '/node_modules': 'node_modules'
      }
    }
  })
}

// 组合任务
const build = parallel(style, script, html, image)
const dev = series(clean, build, serve)

// 导出任务
module.exports = {
  build,
  dev,
  serve
}

# 运行命令,更新代码文件,查看页面变化
gulp dev

此时,不管是 dist 目录下,还是 src 目录下。只要代码发生变化,我们就可以在浏览器上实时看到效果。

附录

1. Win10 配置 hosts

  1. 通过vscode 打开 hosts 文件

    # hosts 文件的路径
    C:\Windows\System32\Drivers\etc
    
  2. 添加 Guthub 相关的内容

    将下面的内容复制,然后追加到 hosts 文件的尾部

    # GitHub Start (chinaz.com) =================================================
    13.229.188.59 github.com
    54.169.195.247 api.github.com
    140.82.113.25 live.github.com
    8.7.198.45 gist.github.com
    
    # 185.199.108.154 github.githubassets.com
    # 185.199.109.154 github.githubassets.com
    185.199.110.154 github.githubassets.com
    # 185.199.111.154 github.githubassets.com
    
    34.196.247.240 collector.githubapp.com
    # 52.7.232.208 collector.githubapp.com
    52.216.92.163 github-cloud.s3.amazonaws.com
    
    199.232.96.133 raw.githubusercontent.com
    151.101.108.133 user-images.githubusercontent.com
    
    151.101.108.133 avatars.githubusercontent.com
    151.101.108.133 avatars0.githubusercontent.com
    151.101.108.133 avatars1.githubusercontent.com
    151.101.108.133 avatars2.githubusercontent.com
    151.101.108.133 avatars3.githubusercontent.com
    151.101.108.133 avatars4.githubusercontent.com
    151.101.108.133 avatars5.githubusercontent.com
    151.101.108.133 avatars6.githubusercontent.com
    151.101.108.133 avatars7.githubusercontent.com
    151.101.108.133 avatars8.githubusercontent.com
    151.101.108.133 avatars9.githubusercontent.com
    151.101.108.133 avatars10.githubusercontent.com
    151.101.108.133 avatars11.githubusercontent.com
    151.101.108.133 avatars12.githubusercontent.com
    151.101.108.133 avatars13.githubusercontent.com
    151.101.108.133 avatars14.githubusercontent.com
    151.101.108.133 avatars15.githubusercontent.com
    151.101.108.133 avatars16.githubusercontent.com
    151.101.108.133 avatars17.githubusercontent.com
    151.101.108.133 avatars18.githubusercontent.com
    151.101.108.133 avatars19.githubusercontent.com
    151.101.108.133 avatars20.githubusercontent.com
    # GitHub End ===================================================================
    
    
  3. 保存文件

    ctrl+s 保存,此时如果报:没有权限,点击以管理员身份重试

2. Mac 配置 hosts

  1. 打开终端

  2. 输入 sudo vi /etc/hosts

  3. 输入密码

  4. 进入文件 hosts,然后按 “i”,进入编辑模式

  5. 把你的内容添加到最后

    # GitHub Start (chinaz.com) =================================================
    13.229.188.59 github.com
    54.169.195.247 api.github.com
    140.82.113.25 live.github.com
    8.7.198.45 gist.github.com
    
    # 185.199.108.154 github.githubassets.com
    # 185.199.109.154 github.githubassets.com
    185.199.110.154 github.githubassets.com
    # 185.199.111.154 github.githubassets.com
    
    34.196.247.240 collector.githubapp.com
    # 52.7.232.208 collector.githubapp.com
    52.216.92.163 github-cloud.s3.amazonaws.com
    
    151.101.108.133 raw.githubusercontent.com
    151.101.108.133 user-images.githubusercontent.com
    
    151.101.108.133 avatars.githubusercontent.com
    151.101.108.133 avatars0.githubusercontent.com
    151.101.108.133 avatars1.githubusercontent.com
    151.101.108.133 avatars2.githubusercontent.com
    151.101.108.133 avatars3.githubusercontent.com
    151.101.108.133 avatars4.githubusercontent.com
    151.101.108.133 avatars5.githubusercontent.com
    151.101.108.133 avatars6.githubusercontent.com
    151.101.108.133 avatars7.githubusercontent.com
    151.101.108.133 avatars8.githubusercontent.com
    151.101.108.133 avatars9.githubusercontent.com
    151.101.108.133 avatars10.githubusercontent.com
    151.101.108.133 avatars11.githubusercontent.com
    151.101.108.133 avatars12.githubusercontent.com
    151.101.108.133 avatars13.githubusercontent.com
    151.101.108.133 avatars14.githubusercontent.com
    151.101.108.133 avatars15.githubusercontent.com
    151.101.108.133 avatars16.githubusercontent.com
    151.101.108.133 avatars17.githubusercontent.com
    151.101.108.133 avatars18.githubusercontent.com
    151.101.108.133 avatars19.githubusercontent.com
    151.101.108.133 avatars20.githubusercontent.com
    # GitHub End ===================================================================
    
    
  6. control+c 退出编辑模式

  7. 输入 :wq,保存退出

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,033评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,725评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,473评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,846评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,848评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,691评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,053评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,700评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,856评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,676评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,787评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,430评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,034评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,990评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,218评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,174评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,526评论 2 343

推荐阅读更多精彩内容