什么是Gulp?
Gulp和Webpack的区别
gulp的核心理念是 task runner
- 可以定义自己的一系列任务,等待任务被执行
- 基于文件Stream的构建流
- 我们可以使用gulp的插件体系来完成某些任务
webpack的核心理念是 module bundler
- webpack是一个模块化的打包工具
- 可以使用各种各样的loader来加载不同的模块
- 可以使用各种各样的插件在 webpack 打包的生命周期完成其他的任务
gulp现在常用于做一些自动化任务,比如将打包好的项目文件上传到服务器这种。
gulp相对于webpack的优缺点:
- gulp相对于webpack思想更加的简单、易用,更适合编写一些自动化的任务
- 但是目前对于大型前端项目(Vue、React、Angular)并不会使用gulp来构建,比如默认gulp是不支持模块化的
Gulp的基本使用
- 安装
npm install gulp
- 新建gulpfile.js ```javascript const gulp = require(“gulp”);
// 定义任务 const foo = (cb) => { console.log(“foo”); cb(); };
// gulp4之前的使用方式 gulp.task(“bar”, (cb) => { console.log(“bar”); cb(); });
module.exports = { foo, };
// 默认任务 module.exports.default = (cb) => { console.log(“default task”); cb(); };
3. 运行
`npx gulp foo`<br />想要执行 foo 函数,就输入上面的,如果想执行 bar 函数,就输入 `npx gulp bar`
<a name="jjVAp"></a>
# 创建gulp任务
每个gulp任务都是一个异步的JavaScript函数:
- 此函数可以接受一个callback作为参数,调用callback函数那么任务会结束
- 或者是一个返回 stream、promise、event emitter、child process或observale类型的函数
任务可以是public或者private类型的:
- 公开任务(Public tasks)从gulpfile中被导出(export),可以通过gulp命令直接调用
- 私有任务(Private tasks)被设计为在内部使用,通常作为series() 或 parallel() 组合的组成部分
<a name="dlDud"></a>
# 任务组合series和parallel
gulp提供了两个强大的组合方法:
- 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();
}, 2000);
};
const task3 = (cb) => {
setTimeout(() => {
console.log("task3");
cb();
}, 2000);
};
const seriesTask = series(task1, task2, task3);
const parallelTask = parallel(task1, task2, task3);
const composeTask = series(seriesTask, parallelTask);
module.exports = {
composeTask,
};
读取和写入文件
gulp 暴露了 src() 和 dest() 方法用于处理计算机上存放的文件。
- src() 接受参数,并从文件系统中读取文件然后生成一个Node流(Stream),它将所有匹配的文件读取到内存中并通过流(Stream)进行处理
- 由src() 产生的流(stream)应当从任务(task函数)中返回并发出异步完成的信号
- dest() 接受一个输出目录作为参数,并且它还会产生一个Node流(Stream),通过该流将内容输出到文件中
流(stream)所提供的主要的API是 .pipe() 方法,pipe的原理是什么呢?
- pipe方法接受一个转换流(Transform streams)或可写流(Writable streams)
- 那么转换流或者可写流,拿到数据之后可以对数据进行处理,再次传递给下一个转换流或者可写流
gulp文件匹配
src() 方法接受一个 glob 字符串或由多个 glob 字符串组成的数组作为参数,用于确定那些文件需要被操作
- glob或blog数组必须至少匹配到一个匹配项,否则src()将报错
glob的匹配规则如下:
- (* 一个星号):在一个字符串中,匹配任意数量的字符,包括零个匹配
- (** 两个星号):在多个字符串匹配中匹配任意数量的字符串,通常用在匹配目录下的文件
- (取反!):取反是取相反的值,用法是在匹配值的时候在后面加!进行取反操作
gulp文件监听
gulp提供了watch方法,用于监听文件变化 ```javascript const { src, dest, watch } = require(“gulp”);
const babel = require(“gulp-babel”); const terser = require(“gulp-terser”);
const jsTask = () => { // 从src中读取文件,输出到dist文件夹中 return src(“./src/*.js”) .pipe(babel({ presets: [“@babel/preset-env”] })) .pipe(terser({ mangle: { toplevel: true } })) .pipe(dest(“./dist”)); };
watch(“./src/*/.js”, jsTask);
module.exports = { jsTask, };
<a name="R2gWN"></a>
# gulp处理html文件
1. 安装 gulp-htmlmin 插件
`npm install gulp-htmlmin -d`
2. 使用插件处理
```javascript
const { src, dest } = require("gulp");
const htmlMin = require("gulp-htmlmin");
const htmlTask = () => {
return src("./src/*.html")
.pipe(
htmlMin({
collapseWhitespace: true,
})
)
.pipe(dest("./dist"));
};
module.exports = {
htmlTask,
};
gulp处理js文件
处理js文件需要用到的库:
- @babel/core
- @babel/preset
- gulp-babel
- gulp-terser ```javascript const { src, dest } = require(“gulp”);
const terser = require(“gulp-terser”); const babel = require(“gulp-babel”);
const jsTask = () => { return src(“./src/js/**.js”, { base: “./src” }) .pipe(babel({ presets: [“@babel/preset-env”] })) .pipe(terser({ mangle: { toplevel: true } })) .pipe(dest(“./dist”)); };
module.exports = { jsTask, };
<a name="pNhbj"></a>
# gulp处理less文件
处理less文件需要用到的库:
1. postcss
1. postcss-preset-env
1. gulp-less
1. gulp-postcss
```javascript
const { src, dest } = require("gulp");
const less = require("gulp-less");
const postcss = require("gulp-postcss");
const postcssPresetEnv = require("postcss-preset-env");
const lessTask = () => {
return src("./src/css/*.less", { base: "./src" })
.pipe(less())
.pipe(postcss([postcssPresetEnv()]))
.pipe(dest("./dist"));
};
module.exports = {
lessTask,
};
处理html资源注入
gulp默认处理的文件(css、js等)是不会被引入html文件中的,为了能够实现自动引入到html文件中,我们需要使用插件gulp-inject
- 安装插件
npm install gulp-inject -d
- gulpfile.js中使用 ```javascript const { src, dest } = require(“gulp”);
const inject = require(“gulp-inject”);
const injectHtml = () => { return src(“./dist/.html”) .pipe( inject(src([“./dist/js/.js”, “./dist/css/*.css”]), { relative: true }) ) .pipe(dest(“./dist”)); };
module.exports = { injectHtml, };
3. html文件中使用
我们还需要对打包出来的dist文件夹下的html文件中做一些配置
```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>
<!-- inject:css -->
<!-- endinject -->
</head>
<body>
<!-- inject:js -->
<!-- endinject -->
</body>
</html>
gulp开启本地服务
- 安装插件
npm install browser-sync -D
- 配置使用 ```javascript const browserSync = require(“browser-sync”);
// 搭建本地服务器 const bs = browserSync.create(); const serve = () => { watch(“./src/.html”, series(htmlTask, injectHtml)); watch(“./src/js/.js”, series(jsTask, injectHtml)); watch(“./src/css/.less”, series(lessTask, injectHtml)); bs.init({ port: 8888, open: true, files: “./dist/“, server: { baseDir: “./dist”, }, }); };
<a name="iauPT"></a>
# serve和build组合
1. 安装 clean 插件,用于清除上次打包的数据
```javascript
const { src, dest, watch, series, parallel } = require("gulp");
const htmlMin = require("gulp-htmlmin");
const terser = require("gulp-terser");
const babel = require("gulp-babel");
const less = require("gulp-less");
const postcss = require("gulp-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"));
};
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(lessTask, injectHtml));
bs.init({
port: 8888,
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 = {
buildTask,
serveTask,
};
总结
gulp的本质就是一个用来处理文件流的工具。它可以处理项目中不同类型的文件,原本这一工作需要python或者shell或者nodeJs这种能够操作本地文件的语言或脚本来实现,gulp相当于是基于node提供了一些专门用于处理文件的api,相较于使用其他语言对于前端来说更好上手。