Gulp使用记录

232 阅读5分钟

gulp是前端自动化构建工具之一,可以使用gulp搭建一些不是那么复杂的项目,比如静态官网

1.使用到的依赖

// package.json
{
  "name": "gulp",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "cross-env NODE_ENV=development gulp serve",
    "build": "cross-env NODE_ENV=production gulp build"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.18.5",
    "@babel/plugin-transform-runtime": "^7.18.5",
    "@babel/preset-env": "^7.18.2",
    "browser-sync": "^2.27.10",
    "cross-env": "^7.0.3",
    "del": "^6.1.1",
    "fs-extra": "^10.1.0",
    "gulp": "^4.0.2",
    "gulp-autoprefixer": "^8.0.0",
    "gulp-babel": "^8.0.0",
    "gulp-cssmin": "^0.2.0",
    "gulp-dart-sass": "^1.0.2",
    "gulp-htmlmin": "^5.0.1",
    "gulp-if": "^3.0.0",
    "gulp-nunjucks-render": "^2.2.3",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-uglify": "^3.0.2"
  },
  "dependencies": {
    "@babel/runtime": "^7.18.3"
  }
}

2.编译html文件

  • 下载依赖
npm i gulp-htmlmin gulp-nunjucks-render -D

在项目根目录中新建gulpfile.js文件,开始编写gulp任务

  • html文件主要就是引入模板文件和压缩
const htmlmin = require('gulp-htmlmin'); // 压缩html
const nunjucksRender = require('gulp-nunjucks-render') // render文件

// 页面文件编译
gulp.task('view', function () {
  const options = {
    removeComments: true, // 清除HTML注释
    collapseWhitespace: true, // 压缩HTML
    collapseBooleanAttributes: true, // 省略布尔属性
    removeEmptyAttributes: true, // 删除所有空属性
    removeScriptTypeAttributes: true, // 删除script标签上的type属性
    removeAttributeQuotes: true, // 删除属性上的双引号
    removeStyleLinkTypeAttributes: true, // 删除style和link标签上的type="text/css"属性
    minifyJS: true, // 压缩页面JS
    minifyCSS: true // 压缩页面CSS
  }

  return gulp
    .src([srcResolve('**/*.html'), "!**/_*.html"])
    .pipe(nunjucksRender({
      path: ['src/']
    }))
    .pipe(gulpIf(isProduct, htmlmin(options)))
    .pipe(gulp.dest(BUILD_PATH))
})
  • 模板文件的使用
// _template.html
<header>
  <h1>Header</h1>
</header>

// index.html
<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <script src="/jquery-3.6.0.min.js"></script>
  <script src="./js/index.js"></script>
</head>

<body>
  {% include "template/_header.html" %}
  <div id="root">Hello World!!!!</div>
</body>
</html>

3.编译样式文件

  • 下载依赖
npm i gulp-cssmin gulp-autoprefixer gulp-dart-sass -D
  • css sass等文件的处理就是添加浏览器兼容前缀和压缩
const cssmin = require('gulp-cssmin'); // 压缩css
const autoprefixer = require('gulp-autoprefixer'); // css文件前缀自动补充
const dartSass = require('gulp-dart-sass'); // scss文件编译

// css文件编译
gulp.task('cssmin', function () {
  return gulp
    .src(srcResolve('**/*.css'))
    .pipe(autoprefixer())
    .pipe(gulpIf(!isProduct, sourceMaps.init()))
    .pipe(gulpIf(isProduct, cssmin()))
    .pipe(gulpIf(!isProduct, sourceMaps.write('./')))
    .pipe(gulp.dest(BUILD_PATH))
})
// sass编译
gulp.task('sass', function () {
  return gulp
    .src(srcResolve('**/*.{scss,sass}'))
    .pipe(dartSass.sync().on('error', dartSass.logError))
    .pipe(autoprefixer())
    .pipe(gulpIf(!isProduct, sourceMaps.init()))
    .pipe(gulpIf(isProduct, cssmin()))
    .pipe(gulpIf(!isProduct, sourceMaps.write('./')))
    .pipe(gulp.dest(BUILD_PATH))
})
  • 在使用gulp-autoprefixer依赖之前,需要新建.browserslistrc文件来配置兼容的浏览器
last 2 versions
Android >= 5.0

更多配置可以参考:github.com/browserslis…

4.编译js文件

对于js文件的处理,需要引入babel来转译ES6以上的语法,转译完成后再进行压缩

  • 下载babel相关依赖

其中@babel/runtime@babel/plugin-transform-runtime两个插件是转译generator和async/await语法使用的

npm i @babel/runtime --save
npm i gulp-babel @babel/core @babel/preset-env @babel/plugin-transform-runtime -D
  • 下载js压缩的依赖
npm i gulp-uglify -D
  • 编写.babelrc文件
{
  "presets": ["@babel/preset-env"],
  "plugins": [["@babel/plugin-transform-runtime"]]
}
  • 编译js任务
// js文件编译
gulp.task('script', function () {
  return gulp.src(srcResolve('**/*.js'))
    .pipe(babel())
    .pipe(gulpIf(!isProduct, sourceMaps.init()))
    .pipe(gulpIf(isProduct, uglify()))
    .pipe(gulpIf(!isProduct, sourceMaps.write('./')))
    .pipe(gulp.dest(BUILD_PATH))
})

5.图片,多媒体文件的处理

图片和多媒体文件只要直接复制到编译目录即可

// 复制图片文件
gulp.task('image', function () {
  return gulp.src(srcResolve('**/*.{png,jpg,jpeg,gif}'))
    .pipe(gulp.dest(BUILD_PATH))
})

// 复制视频文件
gulp.task('media', function () {
  return gulp
    .src(srcResolve('**/*.{mp3,wav,mp4,flv}'))
    .pipe(gulp.dest(BUILD_PATH))
})

6.静态目录的处理

在项目一般都有静态文件目录,用于存放一些不用处理的文件(比如jquery),直接复制到dist目录下即可

  • 下载复制目录的依赖
npm i fs-extra -D
// 静态文件目录复制(不需要编译的文件放这里,比如jquery)
gulp.task('copy', async function (done) {
  try {
    await fsExtra.copy('./public/', BUILD_PATH)
    console.log('[Copyfiles] Success!')
    done()
  } catch (error) {
    console.log('[Copyfiles] get an error' + error)
  }
})

7.本地服务器/监听文件变化

使browser-sync依赖启动本地服务器

  • 下载依赖
npm i browser-sync -D
  • 编写监听任务
const webServer = require('browser-sync').create();

// 本地服务器/监听任务
gulp.task('watch', function () {
  webServer.init({
    server: BUILD_PATH,
    port: 3000,
    watch: true,
    open: false,
    ui: false,
    uglify: false
  });
  
  // 文件监听
  gulp.watch('./src/**/*.html', gulp.series('view', (done) => {
    webServer.reload();
    done();
  }));
  gulp.watch('./src/**/*.js', gulp.series('script', (done) => {
    webServer.reload();
    done();
  }))
  gulp.watch('./src/**/*.css', gulp.series('cssmin', (done) => {
    webServer.reload();
    done();
  }))
  gulp.watch('./src/**/*.{scss,sass}', gulp.series('sass', (done) => {
    webServer.reload()
    done();
  }))
  gulp.watch('./src/**/*.{png,jpg,jpeg,gif}', gulp.series('image', (done) => {
    webServer.reload()
    done()
  }))
})

8.清除目录任务

  • 下载依赖
npm i del -D
  • 编写任务
const del = require('del'); // 清空目录

// 清空目录
gulp.task('clean', async function (done) {
  try {
    await del([BUILD_PATH]);
    console.log('[CleanFile] Success!')
    done();
  } catch (error) {
    console.log('[CleanFile] get an error' + error);
  }
});

9.项目中的其它代码

// 是否生产环境
const isProduct = process.env.NODE_ENV === 'production'
// 源码目录
const SRC_PATH = path.resolve(__dirname, 'src');
// 构建目录
const BUILD_PATH = path.resolve(__dirname, 'dist')

/**
 * 源码目录拼接文件后缀方法
 * @param {String} dir
 * @returns
 */
function srcResolve(dir) {
  return path.resolve(SRC_PATH, dir);
}

10.编写启动脚本

// 本地任务
gulp.task('serve', gulp.series('clean', gulp.parallel('copy', 'image', 'media', 'view', 'script', 'cssmin', 'sass'), 'watch'))

// 编译任务
gulp.task('build', gulp.series('clean', gulp.parallel('copy', 'image', 'media', 'view', 'script', 'cssmin', 'sass')))

11.完整的配置代码

const gulp = require('gulp'); // gulp
const htmlmin = require('gulp-htmlmin'); // 压缩html
const uglify = require('gulp-uglify'); // 压缩js
const babel = require('gulp-babel'); // babel
const webServer = require('browser-sync').create(); // 本地服务器
const del = require('del'); // 清空目录
const fsExtra = require('fs-extra'); // 复制文件夹
const nunjucksRender = require('gulp-nunjucks-render') // render文件
const cssmin = require('gulp-cssmin'); // 压缩css
const autoprefixer = require('gulp-autoprefixer'); // css文件前缀自动补充
const dartSass = require('gulp-dart-sass'); // scss文件编译
const gulpIf = require('gulp-if');
const sourceMaps = require('gulp-sourcemaps'); // 生成map文件
const path = require('path');

// 是否生产环境
const isProduct = process.env.NODE_ENV === 'production'
// 源码目录
const SRC_PATH = path.resolve(__dirname, 'src');
// 构建目录
const BUILD_PATH = path.resolve(__dirname, 'dist')

/**
 * 源码目录拼接文件后缀方法
 * @param {String} dir
 * @returns
 */
function srcResolve(dir) {
  return path.resolve(SRC_PATH, dir);
}

// 清空目录
gulp.task('clean', async function (done) {
  try {
    await del([BUILD_PATH]);
    console.log('[CleanFile] Success!')
    done();
  } catch (error) {
    console.log('[CleanFile] get an error' + error);
  }
});

// 静态文件目录复制(不需要编译的文件放这里,比如jquery)
gulp.task('copy', async function (done) {
  try {
    await fsExtra.copy('./public/', BUILD_PATH)
    console.log('[Copyfiles] Success!')
    done()
  } catch (error) {
    console.log('[Copyfiles] get an error' + error)
  }
})

// 复制图片文件
gulp.task('image', function () {
  return gulp.src(srcResolve('**/*.{png,jpg,jpeg,gif}'))
    .pipe(gulp.dest(BUILD_PATH))
})

// 复制视频文件
gulp.task('media', function () {
  return gulp
    .src(srcResolve('**/*.{mp3,wav,mp4,flv}'))
    .pipe(gulp.dest(BUILD_PATH))
})

// 页面文件编译
gulp.task('view', function () {
  const options = {
    removeComments: true, // 清除HTML注释
    collapseWhitespace: true, // 压缩HTML
    collapseBooleanAttributes: true, // 省略布尔属性
    removeEmptyAttributes: true, // 删除所有空属性
    removeScriptTypeAttributes: true, // 删除script标签上的type属性
    removeAttributeQuotes: true, // 删除属性上的双引号
    removeStyleLinkTypeAttributes: true, // 删除style和link标签上的type="text/css"属性
    minifyJS: true, // 压缩页面JS
    minifyCSS: true // 压缩页面CSS
  }

  return gulp
    .src([srcResolve('**/*.html'), "!**/_*.html"])
    .pipe(nunjucksRender({
      path: ['src/']
    }))
    .pipe(gulpIf(isProduct, htmlmin(options)))
    .pipe(gulp.dest(BUILD_PATH))
})

// js文件编译
gulp.task('script', function () {
  return gulp.src(srcResolve('**/*.js'))
    .pipe(babel())
    .pipe(gulpIf(!isProduct, sourceMaps.init()))
    .pipe(gulpIf(isProduct, uglify()))
    .pipe(gulpIf(!isProduct, sourceMaps.write('./')))
    .pipe(gulp.dest(BUILD_PATH))
})

// css文件编译
gulp.task('cssmin', function () {
  return gulp
    .src(srcResolve('**/*.css'))
    .pipe(autoprefixer())
    .pipe(gulpIf(!isProduct, sourceMaps.init()))
    .pipe(gulpIf(isProduct, cssmin()))
    .pipe(gulpIf(!isProduct, sourceMaps.write('./')))
    .pipe(gulp.dest(BUILD_PATH))
})
// sass编译
gulp.task('sass', function () {
  return gulp
    .src(srcResolve('**/*.{scss,sass}'))
    .pipe(dartSass.sync().on('error', dartSass.logError))
    .pipe(autoprefixer())
    .pipe(gulpIf(!isProduct, sourceMaps.init()))
    .pipe(gulpIf(isProduct, cssmin()))
    .pipe(gulpIf(!isProduct, sourceMaps.write('./')))
    .pipe(gulp.dest(BUILD_PATH))
})

// 本地服务器/监听任务
gulp.task('watch', function () {
  webServer.init({
    server: BUILD_PATH,
    port: 3000,
    watch: true,
    open: false,
    ui: false,
    uglify: false
  });

  // 文件监听
  gulp.watch('./src/**/*.html', gulp.series('view', (done) => {
    webServer.reload();
    done();
  }));
  gulp.watch('./src/**/*.js', gulp.series('script', (done) => {
    webServer.reload();
    done();
  }))

  gulp.watch('./src/**/*.{png,jpg,jpeg,gif}', gulp.series('image', (done) => {
    webServer.reload()
    done()
  }))

  gulp.watch('./src/**/*.css', gulp.series('cssmin', (done) => {
    webServer.reload();
    done();
  }))

  gulp.watch('./src/**/*.{scss,sass}', gulp.series('sass', (done) => {
    webServer.reload()
    done();
  }))

})

// 本地任务
gulp.task('serve', gulp.series('clean', gulp.parallel('copy', 'image', 'media', 'view', 'script', 'cssmin', 'sass'), 'watch'))

// 编译任务
gulp.task('build', gulp.series('clean', gulp.parallel('copy', 'image', 'media', 'view', 'script', 'cssmin', 'sass')))