2023-08-18
前端工程化
00
请注意,本文编写于 145 天前,最后修改于 145 天前,其中某些信息可能已经过时。

目录

Gulp是什么?
Grunt vs Gulp
Gulp vs Webpack
创建Gulp任务
任务组合series和parallel
读写文件&转换
gulp案例

本文简单介绍gulp概念及基本使用

Gulp是什么?

  • 官网
  • gulp是一个基于流的自动化构建工具
  • 它是一个工具包,可以帮你自动化和增加你的工作流

Grunt vs Gulp

  • grunt运用配置的思想来写打包脚本一切皆配置,配置项比较多且不同的插件会有扩展字段,认知成本高;更像一个工具库,为你提供各种螺丝刀,采用流式写法来编写构建脚本
  • grunt默认采用串行的方式执行任务,想要并行则以大任务包含小任务, 一种树形结构)的方式运行,不灵活;gulp并行串行课随便组装
  • gulp 流的形式 是将文件写入内存,而grunt是写入临时文件,所以gulp构建项目比grunt

先有的grunt再有的gulpgulp一诞生就迅速取代了grunt

Gulp vs Webpack

gulp的核心理念是task runner

  • 可以定义自己的一系列任务,等待任务被执行;
  • 基于文件Stream的构建流;
  • 我们可以使用Gulp的插件体系来完成某些任务

webpack的核心理念是module bundler

  • webpack 是一个模块化打包工具
  • 可以使用各种各样的loader来加载不同的模块
  • 可以使用各种各样的插件在webpack打包的生命周期完成其他的任务;

gulp相对与webpack的优缺点:

  • gulp相对webpack思想更加的简单、易用,更适合编写一些自动化的任务
  • 但是大型项目一般不会使用gulp来构建,gulp默认也是不支持模块化的

创建Gulp任务

每个Gulp任务都是一个异步的JavaScript函数:

  • 此函数可以接受一个callback作为参数,调用callback函数表示任务结束
  • 或者是返回一个steampromiseevent emmitterchild process 或者observer类型的函数

任务可以是public或者private类型的

  • 公开任务 从gulpfile.js中被导出,可以通过npx gulp [command]命令直接调用;
  • 私有任务 被设计为内部使用,通常作为series()parallel()组合的组成部分;
javascript
// 定义任务 `npx gulp foo` module.exports.foo = (cb) => { console.log("foo"); cb(); } // 默认任务 `npx gulp` module.exports.default = (cb) => { console.log("default task"); cb(); } // gulp4之前, 定义任务的方式 `npx gulp bar` const gulp = require('gulp'); gulp.task("bar", (cb) => { console.log("bar"); cb(); }) // 私有任务 const abc = (cb) => { cb(); } module.exports.def = () => console.log('不是任务'); // npx gulp def // [20:47:04] The following tasks did not complete: def // [20:47:04] Did you forget to signal async completion?

任务组合series和parallel

  • series() 串行任务组合
  • parallel() 并行任务组合

他们可以接受任意数量的任务函数或者已经组合的操作

javascript
const { series, parallel } = require('gulp'); const task1 = (cb) => { setTimeout(() => { console.log("task1"); cb(); }, 2000); } const task2 = (cb) => { setTimeout(() => { console.log("task2"); cb(); }, 3000); } const seriesTask = series(task1, task2); const parallelTask = parallel(task1, task2); const composeTask = series(parallelTask, seriesTask); module.exports = { seriesTask, parallelTask, composeTask } // 1. npx gulp seriesTask // Finished 'seriesTask' after 5.01 s // 2. npx gulp parallelTask // Finished 'parallelTask' after 3 s // 3. npx gulp composeTask // 串行 parallelTask 和 parallelTask 3+5 = 8

读写文件&转换

gulp暴露了src()dist()方法处理计算机上存放的文件

  • src()  接受参数从文件系统中读取文件然后生成一个Node流,它将所有匹配的文件读到内存中并通过流进行处理
    • src 产生的流应从任务中返回并发出异步完成的信号;
  • dest()  接受一个输出目录作为参数,并且他还会产生一个Node流,通过该流将内容输出到文件中

流所提供的主要API.pipe()方法 其原理是什么呢?

  • pipe 方法接受一个转换流可写流
  • 那么转换流或者可写流,拿到数据后可以对数据进行处理,再次传递给下一个转换流或者可写流;

pipe方法可以做哪里事情?

  • 如果希望将es6转换成es5,可以使用babel插件
  • 如果希望对代码进行压缩和丑化,可以使用uglify或者terser插件

glob文件匹配

  • src 方法接受一个glob字符串或有多个glob字符串组成的数组作为参数,用于确定哪些文件要被执行
  • glob 的匹配规则 可以看我的另一篇文章 glob模式匹配
    • *.js 匹配当前目录下任意js文件
    • script/**/*.js script目录下的任意目录下的任意js文件
    • ['script/**/*.js', '!script/vender']排除script/vender目录后,script目录下的任意目录下的任意js文件
javascript
const gulp = require('gulp'); const babel = require("gulp-babel"); const jsTask = async () => { return gulp.src('./src/**/*.js') .pipe(babel()) // .pipe(terser({mangle: {toplevel: true }})) .pipe(gulp.dest("./dist")) } module.exports = { jsTask }

gulp案例

详细案例点击这里

javascript
const { src, dest, watch, series, parallel } = require('gulp'); const htmlMin = require('gulp-htmlmin'); const babel = require('gulp-babel'); const terser = require('gulp-terser'); const less = require('gulp-less'); // less const postcss = require('gulp-postcss'); // postcss const postcssPresetEnv = require('postcss-preset-env'); const inject = require('gulp-inject'); const browserSync = require('browser-sync'); const del = require('del'); const htmlTask = () => { return src("./src/*.html", {base: "./src"}) .pipe(htmlMin({ collapseWhitespace: true })) .pipe(dest("./dist")) } const jsTask = () => { return src("./src/js/**.js", {base: "./src"}) .pipe(babel({presets: ["@babel/preset-env"]})) .pipe(terser({mangle: {toplevel: true}})) .pipe(dest("./dist")) } const lessTask = () => { return src("./src/css/*.less", {base: "./src"}) .pipe(less()) .pipe(postcss([postcssPresetEnv()])) .pipe(dest("./dist")) } /** * 配合 * <!-- inject:css --> <!-- endinject --> * <!-- inject:js --> <!-- endinject --> * 使用 */ const injectHtml = () => { return src("./dist/*.html") .pipe(inject(src(["./dist/js/*.js", "./dist/css/*.css"]), {relative: true})) .pipe(dest('./dist')) } // 搭建本地服务器 const bs = browserSync.create(); const serve = () => { watch("./src/*.html", series(htmlTask, injectHtml)); watch("./src/js/*.js", series(jsTask, injectHtml)); watch("./src/css/*.less", series(jsTask, lessTask)); bs.init({ port: 8080, open: true, files: "./dist/*", server: { baseDir: "./dist" } }) } const clean = () => { return del(["dist"]) } const buildTask = series(clean, parallel(htmlTask, jsTask, lessTask), injectHtml); const serveTask = series(buildTask, serve); module.exports = { htmlTask, serveTask, buildTask }

本文作者:郭敬文

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!