系统化学习前端之gulp
gulp 是什么
基于流的自动化构建工具
gulp 单任务
gulp 执行单个任务可以直接通过定义任务,执行任务名方式来完成任务。
gulp4.0 之前
-
安装依赖
npm install -D gulp
-
配置文件 gulpfile.js
具名任务
-
定义任务
const gulp = require('gulp') gulp.task('job', (cb) => { console.log('job') cb() })
-
执行 gulp 指令
npx gulp job
不具名任务
-
定义任务
const gulp = require('gulp') gulp.task('default', (cb) => { console.log('default') cb() })
-
执行 gulp 指令
npx gulp
-
gulp4.0 之后
-
安装依赖
npm install -D gulp
-
配置文件 gulpfile.js
具名任务
-
定义任务
const job = (cb) => { console.log('job') cb() // 使用回调结束 task,不使用回调会导致报错 task not complete } module.exports = { job }
-
执行 gulp 指令
npx gulp job
不具名任务
-
定义任务
const job = (cb) => { console.log('default') cb() } module.exports.default = job
-
执行 gulp 指令
npx gulp
注意:每个 gulp 任务都是一个异步 JavaScript 函数,任务结束需要满足以下任一条件:
- 任务函数可以接收一个 callback 作为参数,调用回调函数则任务结束。
- 任务函数返回 stream, promise, event emitter, child process 或 observable 类型的函数则任务结束。
-
gulp 多任务
gulp 执行多个任务可以通过 gulp 内置 api 来进行任务组合执行,gulp 任务组合 api 有 series 和 parallel,两者均可以接收任意数量的任务函数或者组合后的任务组合。
series
串行任务组合。series() 接收的任务函数或者任务组合会按照串行执行,即同一时间只执行单个任务,当上一个任务完成再执行下一个任务。
-
定义任务
const { series, parallel } = require('gulp') const task1 = (cb) => { setTimeout(() => { console.log('task1') cb() }, 1000) } const task2 = (cb) => { setTimeout(() => { console.log('task2') cb() }, 1000) } const task3 = (cb) => { setTimeout(() => { console.log('task3') cb() }, 1000) } module.exports.default = series(task1, task2, task3)
-
执行指令
npx gulp
parallel
并行任务组合。parallel() 接收的任务函数和任务组合会按照并行执行,即同一时间执行多个 parallel 接收的任务。
-
定义任务
const { series, parallel } = require('gulp') const task1 = (cb) => { setTimeout(() => { console.log('task1') cb() }, 1000) } const task2 = (cb) => { setTimeout(() => { console.log('task2') cb() }, 1000) } const task3 = (cb) => { setTimeout(() => { console.log('task3') cb() }, 1000) } module.exports.default = parallel(task1, task2, task3)
-
执行指令
npx gulp
series / parallel 复合
-
定义任务
const { series, parallel } = require('gulp') const task1 = (cb) => { setTimeout(() => { console.log('task1') cb() }, 1000) } const task2 = (cb) => { setTimeout(() => { console.log('task2') cb() }, 1000) } const task3 = (cb) => { setTimeout(() => { console.log('task3') cb() }, 1000) } const seriesTask = series(task1, task2, task3) const parallelTask = parallel(task1, task2, task3) const composeTask = series(seriesTask, parallelTask) module.exports.default = composeTask
-
执行指令
npx gulp
读取/写入文件
gulp 定义任务,执行任务都是在 gulp 配置文件中操作的。实际项目处理,gulpfile.js 读取外部文件,处理后返回并写入文件,因此,需要使用 gulp 读取和写入文件 api 来处理外部文件,gulp 读取、写入文件 api 分别为 src 和 dest。
src
src 接收文件路径作为参数,以 stream 的方式读取文件。单个文件路径以字符串形式接收,多个文件路径以数组方式接收。
文件路径可以以正则形式进行匹配,至少有一个匹配,否则报错。
匹配规则:
1. `/src/*.js`
表示仅匹配 src 目录下的所有js,对于 /src/js/ 目录下的 js 是无法匹配的。
2. `/src/**/*.js`
表示匹配 src 目录下的所有js,包含 /src/js/ 目录下的 js 。
3. `[ '/src/**/*.js', '!script/' ]`
表示匹配 src 目录下的所有js,包含 /src/js/ 目录下的 js ,但不包含 /src/script/ 目录下的 js 。
dest
dest 接收输入目录作为参数,将 stream 写入到文件中。
src/dest 用法
-
文件结构
main.js
const sum = (x, y) => { return x + y } const res = sum(x, y) console.log(res)
gulpfile.js
const { src, dest } = require('gulp') const babel = require('gulp-babel') const uglify = require('gulp-uglify') const job = (cb) => { return src('./src/*.js') .pipe(babel({ presets: ['@babel/preset-env'] })) .pipe(uglify()) .pipe(dest('./dist/')) } module.exports.default = job
-
安装 gulp 插件及依赖
npm install -D gulp-babel @babel/core @babel/preset-env npm install -D gulp-uglify
-
启动 gulp
npx gulp
注意: src,dest读取和写入文件均是以 stream 流的方式进行的。
-
pipe 顾名思义:管道,用于”运输“ stream 流,对 stream 流进行处理以后,传递给下一个pipe。
-
gulp-babel 插件,用于 ES6 语法转换为 ES5。
-
gulp-uglify 插件,用于压缩 js 文件。
-
监听文件
开发过程中,js 文件一旦发生修改,gulp 需要重新启动才能进行 stream 流的处理操作。gulp 提供了一个监听文件内容变化的 api ,用于监听文件,一旦内容变化,则原有任务会重新执行。监听文件变化的 api 是 watch 。
watch
watch 接收两个参数,一个是需要监听的文件路径,同样可以使用正则匹配;另一个是文件内容变化需要执行的任务或任务组合。
gulpfile.js
const { src, dest, watch } = require('gulp')
const babel = require('gulp-babel')
const uglify = require('gulp-uglify')
const job = (cb) => {
return src('./src/*.js')
.pipe(babel({ presets: ['@babel/preset-env'] }))
.pipe(uglify())
.pipe(dest('./dist/'))
}
watch('./src/*.js', job)
module.exports.default = job
项目简单配置案例
gulpfile.js
const { series, parallel, src, dest, watch } = require('gulp')
const htmlMin = require('gulp-htmlmin')
const less = require('gulp-less')
const postCss = require('gulp-postcss')
const postPresetEnv = require('postcss-preset-env')
const cssMin = require('gulp-cssmin')
const babel = require('gulp-babel')
const uglify = require('gulp-uglify')
const inject = require('gulp-inject')
const browser = require('browser-sync')
const clean = require('gulp-clean')
const htmlTask = () => {
return src('./src/index.html')
.pipe(htmlMin({
collapseWhitespace: true // 压缩 html
}))
.pipe(dest('./dist/'))
}
const cssTask = () => {
return src('./src/css/**/*.less', { base: './src' }) // 保持对应目录结构不变
.pipe(less()) // 处理 less
.pipe(postCss([postPresetEnv()])) // 自动增加浏览器前缀
.pipe(cssMin()) // 压缩 css
.pipe(dest('./dist/'))
}
const jsTask = () => {
return src('./src/js/**/*.js', { base: './src' })
.pipe(babel({ presets: ['@babel/preset-env'] })) // 编译 ES6 -> ES5
.pipe(uglify()) // 压缩 js
.pipe(dest('./dist/'))
}
const injectTask = () => {
return src('./dist/index.html')
.pipe(
inject(
src(['./dist/**/*.js','./dist/css/**/*.css'], { read: false }),
{ relative: true } // 相对路径引入
)
)
.pipe(dest('./dist/'))
}
// 搭建本地服务器
const server = browser.create()
const serverTask = () => {
watch("./src/*.html", series(htmlTask, injectTask))
watch("./src/**/*.less", series(cssTask, injectTask))
watch("./src/**/*.js", series(jsTask, injectTask))
server.init({
port: 3000,
open: true,
files: './dist/*',
server: {
baseDir: './dist/'
}
})
}
// 清空 dist 目录
const cleanTask = () => {
return src('dist')
.pipe(clean())
}
const buildTask = series(cleanTask, parallel(htmlTask, cssTask, jsTask), injectTask)
const devTask = series(buildTask, serverTask)
module.exports = {
devTask,
buildTask
}
package.json
{
"scripts": {
"dev": "gulp devTask",
"build": "gulp buildTask",
},
}
更多配置可以查看 gulp 插件配置
本文来自博客园,作者:深巷酒,转载请注明原文链接:https://www.cnblogs.com/huangminghua/p/17144623.html