gulp--搭建基础构建过程

2021-06-27  本文已影响0人  伍超波

定义

官方定义是the streaming build system,基于流的构建系统。使用文件流目的是实现构建管道的概念,这样使用插件的时候,就可以有一种比较统一的方式。

基本使用https://gulpjs.com/

组合任务

// series 组合串行任务
// parallel 同步执行任务
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)

// 让多个任务同时执行,css和js可以同步执行
exports.bar = parallel(task1, task2, task3)

异步任务

const fs = require('fs')

// 1. 通过回调方式执行,错误优先
exports.callback = done => {
  console.log('callback task')
  done()
}
// 多任务同时执行时,报错后,后面的任务不会再次执行
exports.callback_error = done => {
  console.log('callback task')
  done(new Error('task failed'))
}

// 2. promise方式
exports.promise = () => {
  console.log('promise task')
  // 需要return Promise对象,不需要返回任何的值,因为gulp会忽略所有返回参数
  return Promise.resolve()
}

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

// 3. es7 提供的async,node版本为8以上可以使用
const timeout = time => {
  return new Promise(resolve => {
    setTimeout(resolve, time)
  })
}

exports.async = async () => {
  await timeout(1000)
  console.log('async task')
}

// 4. 较为常见的stream方式,读取文件流,返回stream对象
exports.stream = () => {
  // 读取文件文件流
  const read = fs.createReadStream('yarn.lock')
  // 写入文件流
  const write = fs.createWriteStream('a.txt')
  // 起到文件复制的作用,从一个流 流到另一个流,将read的写入write中
  read.pipe(write)
  //结束时机是read end事件触发的时候,read都有一个end事件
  return read
}

// 模拟gulp监听end事件
exports.stream = done => {
  const read = fs.createReadStream('yarn.lock')
  const write = fs.createWriteStream('a.txt')
  read.pipe(write)
  // gulp接收到了readStream,会注册一个end事件,去监听这个任务的结束
  read.on('end', () => {
    done()
  })
}

构建过程核心原理

读入:读取文件、 加工:压缩文件 、输出:写入文件

屏幕快照 2021-06-20 22.36.04.png
const fs = require('fs')
const { Transform } = require('stream')

exports.default = () => {
  // 文件读取流
  const readStream = fs.createReadStream('normalize.css')

  // 文件写入流
  const writeStream = fs.createWriteStream('normalize.min.css')

  // 文件转换流
  const transformStream = new Transform({
    // 核心转换过程
    transform: (chunk, encoding, callback) => {
      const input = chunk.toString()
      const output = input.replace(/\s+/g, '').replace(/\/\*.+?\*\//g, '') // 将css注释删掉
      // node的callback是错误优先的
      callback(null, output)
    }
  })

  // return 出去,gulp就可以根据流的状态判断任务是否完成
  return readStream
    .pipe(transformStream) // 转换
    .pipe(writeStream) // 写入
}

gulp 文件操作API

对比node的文件操作API,gulp的更加强大和更容易使用,对于文件的转换流,一般都是使用插件来完成。流程一般为通过gulp的src, dest两个方法,来实现文件的读写。

const { src, dest } = require('gulp')
const cleanCSS = require('gulp-clean-css')
const rename = require('gulp-rename')

exports.default = () => {
  return src('src/*.css')
    .pipe(cleanCSS())
    .pipe(rename({ extname: '.min.css' }))
    .pipe(dest('dist'))
}

gulp 实战

  1. gulp样式编译。
const {src, dest} = require('gulp')
const sass = require('gulp-sass') // 基本每个插件都返回一个函数

const style = () => {
  return src('src/assets/styles/*.scss', {base: 'src'}) // 当使用 dest() 写入文件系统时,将从输出路径中删除 base ,以保留目录结构。这里指定下base是src。
    .pipe(sass({outputStyle: 'expanded'})) // sass默认不处理下滑线的scss文件,会认为下划线的是主文件(main.scss)依赖的文件,所以不会转换会被忽略掉,例如_icons.scss
    .pipe(dest('dist')) // 以覆盖的方式写入,不会删掉以前的文件
}

module.exports = {
  style
}

  1. 脚本编译(es6)
const {src, dest} = require('gulp')
const babel = require('gulp-babel') // 基本每个插件都返回一个函数
// 单独安装gulp-babel只提供一个转换平台,具体转换流程是依赖插件的,但这个只是帮助调用@babel/core里面的api,所以要安装其他babel插件

const script = () => {
  return src('src/assets/scripts/*.js', {base: 'src'}) // 当使用 dest() 写入文件系统时,将从输出路径中删除 base ,以保留目录结构。这里指定下base是src。
    .pipe(babel({presets: ['@babel/preset-env']})) // 要是没有写@babel/preset-env,则有转换无效的感觉
    .pipe(dest('dist')) // 以覆盖的方式写入,不会删掉以前的文件
}

module.exports = {
  script
}
  1. 页面模板编译
const {src, dest} = require('gulp')
const swig = require('gulp-swig') // 基本每个插件都返回一个函数

const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}

// 注意:有时直接修改模板,不会立即热更新,主要是因为swig模板引擎缓存的机制导致页面不会变化
// 此时,需要额外将swig选项中的cache设置为false
const page = () => {
  return src('src/*.html', { base: 'src' })
    .pipe(plugins.swig({ data, defaults: { cache: false } })) // 防止模板缓存导致页面不能及时更新
    .pipe(dest('temp'))
    .pipe(bs.reload({ stream: true }))
}
module.exports = {
  page
}

  1. 图片压缩和处理图片字体,因为图片包含一些二进制信息,在我们的生产环境是不需要用到的。
const {src, dest} = require('gulp')
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'))
}

module.exports = {
  image,
  font
}

  1. 删除文件和其他文件
const {src, dest} = require('gulp')

const del = require('del')

const extra = () => {
  return src('public/**', { base: 'public' })
    .pipe(dest('dist'))
}

const clean = () => {
  return del(['dist'])
}
  1. 自动加载插件
  1. 开发服务器:热更新开发服务器
const browserSync = require('browser-sync')

// 通过create方法创建服务
const bs = browserSync.create()
// 启动服务
// 单独定义一个任务启动
const serve = () => {
  bs.init({
    server: {
      notify: false,
      port: 3002,
      open: false, // 是否自动打开浏览器
      // 网页跟目录,填写网页加工过后的根目录
      baseDir: 'dist',
      // 优先与basedir,先找routes里面配置的文件,没有再找baseDir的
      routes: {
        '/node_modules': 'node_modules',
      },
    },
  })
}

module.exports = {
serve
}

  1. 监听变化以及构建优化
  1. 先在bs.init 下的files配置写入配置
const serve = () => {
  bs.init({
    server: {
      notify: false,
      port: 3002,
      files: 'dist/**', // 用来去被browsersync监听的文件,可以配置通配符,指定被监听的文件
      open: false, // 是否自动打开浏览器
      // 网页跟目录,填写网页加工过后的根目录
      baseDir: 'dist',
      // 优先与basedir,先找routes里面配置的文件,没有再找baseDir的
      routes: {
        '/node_modules': 'node_modules',
      },
    },
  })
}
  1. 监听src下面文件的变化
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)
  // 在开发阶段一般不会经常改,所以不需要监听以下几个文件
  // 只要在发布上线前,编译一遍就好了
  // 这样开发环境就减少了一起编译
  watch(['src/assets/images/**', 'src/assets/fonts/**', 'public/**'], bs.reload) // 三种文件变化过后,执行reload方法

  bs.init({
    server: {
      notify: false,
      port: 3002,
      files: 'dist/**', // 用来去被browsersync可以配置通配符,指定被监听的文件
      open: false, // 是否自动打开浏览器
      // 网页跟目录,填写网页加工过后的根目录
      baseDir: 'dist',
      // 优先与basedir,先找routes里面配置的文件,没有再找baseDir的
      routes: {
        '/node_modules': 'node_modules',
      },
    },
  })
}
  1. useref文件引用处理
// 结果放在dist,构建放在temp,目的是防止读写冲突,写不进文件
const useref = () => {
  return (
    src('temp/*.html', { base: 'temp' }) // 这里找的是打包后的目录下的文件,temp是打包后的文件夹
      .pipe(plugins.useref({ searchPath: ['temp', '.'] })) // 确定注释里面的文件,可以在哪个目录文件找,这里是指定temp文件夹找,找不到就在根目录下找
      // useref处理后会有三种文件类型html js css
      .pipe(plugins.if(/\.js$/, plugins.uglify())) // gulp-if用来判断是哪种类型的文件
      .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
      .pipe(
        plugins.if(
          /\.html$/,
          plugins.htmlmin({
            collapseWhitespace: true, // 自动压缩空白符号和换行符
            minifyCSS: true, // 压缩内敛的css
            minifyJS: true, // 压缩内敛的js
          })
        )
      )
      .pipe(dest('dist'))
  )
}
  1. 补充
"scripts": {
    "clean": "gulp clean",
    "build": "gulp build",
    "develop": "gulp develop"
  },
上一篇下一篇

猜你喜欢

热点阅读