Gulp 自动化构建工具
前言
前端构建工具 gulp 的学习,本文由网络文章以及教程资料整理
gulp 介绍
在前后端分离的模式中, node 充当的是自动化构建工具
常见的自动化构建工具
gruntgulpwebpack
而这篇主要记录的是 gulp ,没错,因为 gulp 相对来说,比较简单(菜鸡狗头保命)
gulp 是一个基于流的自动化构建工具。他可以监听项目文件、读写文件,管理和执行任务(Task)。掌握 gulp 的几个关键 API 就可以完成你的大部分构建需求
gulp.task注册一个任务gulp.src以文件流的形式获取文件gulp.dest保存文件到具体地址gulp.run执行任务gulp.series让任务按顺序执行gulp.watch监控文件改动
gulp 最大的特点是引入流的概念,同时提供一系列常用的插件去处理流,流可以在插件之间传递
gulp 的 API 简单,使用起来非常容易,但同时对于复杂应用同样存在缺点,就是需要写非常多的复杂配置。接下来就看看如何使用 gulp 的这几个 API,还有哪些插件可以使用
gulp 安装使用
1. 全局安装 gulp
npm install -g gulp2. 作为项目开发依赖(DevDependencies)安装
npm install -D gulp3. gulpfile.js
在项目根目录文件夹下创建 gulpfile.js 文件
const gulp = require(gulp);
// 创建一个默认任务
gulp.task('default', function() {
// 任务代码
})4. 运行 gulp
项目根目录下 cmd 执行 gulp
gulp默认的名为 default 的任务(task) 将会被运行,想要单独运行特定的任务,可在定义任务 (task) 后,输入执行 gulp <task> <othertask>
gulp task1 task2gulp 核心 api
1. task([taskName], taskFunction)
定义任务,gulp 的执行由一个个单独的任务组成的
taskName任务名称taskFunction任务具体的执行函数
在 gulpfile.js 中
const gulp = require('gulp');
// 定义名为 hello 的任务
gulp.task('hello', () => {
console.log('hello gulp!')
})在 cmd 窗口中执行 hello 任务
gulp hellogulp -f gulpfile2.js hello 可运行指定的 gulp 文件和任务
注意
gulp 4.0 版本 要求在任务内,返回一个 promise 对象,需要对其手动关闭,否则任务不会关闭,可通过以下方式将其关闭
const gulp = require("gulp");
// 1 方式1
gulp.task("hello", done => {
console.log("hello gulp!");
// 任务执行完毕之后,需要手动调用done来结束任务
done();
});
// 2 方式2 返回一个promise对象
gulp.task("hello1", () => {
return new Promise((resolve, reject) => {
console.log("hello gulp");
resolve();
});
});
// 3 方式3 返回 gulp的strem流
gulp.task("copy", () => {
return (
gulp
.src("src/index.html")
.pipe(gulp.dest("dist/"))
);
});2. src(globs, [options]) 和 dest(directory, [options])
src 获取文件,以文件流的形式
globs获取文件的正则写法options配置信息,可选
dest 保存文件流到具体的地址上
directory保存的目标地址options配置信息,可选
在 gulpfile.js 中编写任务
const gulp = require("gulp");
// 编写一个拷贝任务
gulp.task("copy", () => {
// 1 获取根目录下的src下的一个文件index.html
return (
gulp
.src("src/index.html")
// 2.1 pipe是gulp内置的管道处理函数,固定写法 可以处理gulp.src内的文件流
// 2.2 dest 复制到dist目录下
.pipe(gulp.dest("dist/"))
);
});以上任务会获取 src 文件夹下的 index.html 文件,将其通过 pipe 复制到 dist/ 文件夹下
pipe是gulp内置的管道处理函数,可处理gulp.src内的文件流return一个文件流表示结束该任务
在 cmd 中执行 copy 任务
gulp copy3. series(...tasks)
gulp 任务不会按照顺序执行的,需要使用 series 来指定执行顺序
const gulp = require("gulp");
// 1 定义任务
gulp.task("hello1", done => {
console.log("hello1");
done();
});
// 2 定义任务
gulp.task("hello2", done=> {
console.log("hello2");
done();
});
// 3 按顺序执行任务
gulp.task("sequence",gulp.series([
'hello1',
'hello2',
]))4. watch(globs, [options], [task])
监控文件的改动,进而触发对应的任务,如 sass 文件改动,触发自动编译
globs获取文件的正则写法options配置信息,可选task文件发生改动后执行的任务,可选
watcher.on(eventName, eventHandler)
watcher 指的是 watch 函数的返回值,它可以继续绑定对应的事件,进而触发后续的逻辑
eventName 支持的事件名称
addaddDirchangeunlinkunlinkDirreadyerrorall
eventHandler 事件的执行函数
gulp 常用插件
1. del(patterns, [options])
patterns使用正则或数组来匹配要删除的源文件options配置信息,可选
- 安装
npm install del -D- 编写删除任务
const gulp = require("gulp");
const del = require("del");
// 编写删除任务 任务名为del
gulp.task("del", () => {
// 删除目录下名字为dist的文件夹
return del(["dist"]);
});- 执行任务
gulp del2. gulp-sass 和 node-sass
gulp-sass 和 node-sass 是用来将 sass 文件编译成 css 文件
- 安装
npm install node-sass gulp-sass -D- 编写任务
const gulp = require("gulp");
const sass = require("gulp-sass");
// 将 node-sass导出为 sass的编译器 compiler 使用sass就可以直接编译css
sass.compiler = require("node-sass");
gulp.task("css", () => {
return gulp
.src("src/css/*.scss")
// 执行编译
.pipe(sass())
.pipe(gulp.dest("dist/css/"));
});- 执行
gulp css3. gulp-autoprefixer
自动添加浏览器前缀
- 安装
npm i gulp-autoprefixer -D- 编写任务
const gulp = require("gulp");
const sass = require("gulp-sass");
sass.compiler = require("node-sass");
// 1 引入自动添加浏览器前缀的文件
const autoprefixer = require("gulp-autoprefixer");
gulp.task("css", () => {
return gulp
.src("src/css/*.scss")
.pipe(sass())
.pipe(
// 2 添加最新的各大主流浏览器的两个版本的兼容性前缀
autoprefixer({
browsers: ["last 2 versions"]
})
)
.pipe(gulp.dest("dist/css/"));
});- 执行任务
gulp css4. gulp-sourcemaps
提供编译前的 sass 文件到编译后的 css 文件的映射,生成 map 文件。
- 安装
npm i gulp-sourcemaps -D- 编写任务
const gulp = require("gulp");
const sass = require("gulp-sass");
sass.compiler = require("node-sass");
const autoprefixer = require("gulp-autoprefixer");
// 1 引入包
const sourcemaps = require("gulp-sourcemaps");
gulp.task("css", () => {
return gulp
.src("src/css/*.scss")
// 2 获取到源文件后先记录以下
.pipe(sourcemaps.init())
// 3 编译sass文件
.pipe(sass())
// 4 添加兼容性前缀
.pipe(
autoprefixer({
browsers: ["last 2 versions"]
})
)
// 5 在css文件夹内生成map文件
.pipe(sourcemaps.write("."))
// 6 将map文件和sass文件一起放入到对应的目录下
.pipe(gulp.dest("dist/css/"));
});- 执行任务
gulp css5. gulp-babel
babel 是一个专门处理 js 编译的库,如将 es6 编译成 es5 等
- 安装
npm i gulp-babel @babel/core @babel/preset-env -D- 编写任务
const gulp = require("gulp");
const sourcemaps = require("gulp-sourcemaps");
// 1 导入babel包
const babel = require("gulp-babel");
gulp.task("js", () => {
return gulp
.src("src/js/*.js")
// 2 记录编译前的 es6的js
.pipe(sourcemaps.init())
// 3 使用babel进行编译
.pipe(babel())
// 4 js 生成js的map文件
.pipe(sourcemaps.write("."))
// 5 存放到对应的地址
.pipe(gulp.dest("dist/js/"));
});- 执行任务
gulp js如果需要将 es7 或者 es8 编译为 es6 或者 es5 呢
在根目录下新建文件 .babelrc 对齐进行配置
{
"presets": [
["@babel/preset-env", {
"targets": {
"browsers": ["last 2 years"]
}
}]
]
}presets 为预设的意思,它的值可以进行扩展配置,"@babel/preset-env" 是一个模块,里面默认包含了 将 es6 => es5 的设定,后期需要增加不同的版本的编译时,只要拓展该字段即可。
以上用法为babel 最常见的使用方式
6. gulp-file-include
提供了文件合并的功能,可以理解为 类似 gulp 中的渲染模板插件,可以实现前端标签的组件化,如 header.html 组件,nav.html 组件等
- 安装
npm install gulp-file-include -D- 编写任务
const gulp = require("gulp");
// 1 导入包
const fileInclude = require("gulp-file-include");
gulp.task("html", () => {
return gulp
// 2 获取页面文件
.src("src/index.html")
.pipe(
// 3 加载模版文件
fileInclude({
// 3.1 模版语法的识别符号
prefix: "@@",
// 3.2 定义组件路径
basepath: "src/components/",
// 3.3 context为关键字,内部的变量是组件内部可以使用的变量
context: {
// 3.4 定义整个项目的变量 名为 title 值为 "我们的页面"
title: "我们的页面"
}
})
)
// 4 合并成功后,将html文件放置到dist文件夹下
.pipe(gulp.dest("dist/"));
});- 执行任务
gulp html组件 header.html
在 src/components/ 内,新增组件文件 名为 header.html,输入内容
<h1>公共的头部</h1>
<h2>gulpflie.js文件的html任务 中定义的变量 @@page</h2>
<h2>index.html文件中传入的变量名 @@title</h2>页面 index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
@@include("header.html",{"page":"index"})
</body>
</html>7. browser-sync
实现编辑文件时,浏览器自动刷新,提高编码效率
- 安装
npm install browser-sync -D- 编写任务
const gulp = require("gulp");
const fileInclude = require("gulp-file-include");
// 1 引入文件
const browserSync = require("browser-sync");
// 2 编写编译html的任务
gulp.task("html", () => {
return gulp
.src("src/index.html")
.pipe(
fileInclude({
prefix: "@@",
basepath: "src/components/",
context: {
baseSrc: "."
}
})
)
.pipe(gulp.dest("dist/"));
});
// 3 开启服务器和动态更新的任务
gulp.task("serve", () => {
browserSync({
// 3.1 开启本地服务器
server: {
// 3.2 网站的路径
baseDir: "dist",
// 3.3 端口
port: 8080
},
// 3.4 关闭浏览器右上方的黑色的提示框
notify: false
});
// 4 使用watch开监控页面的变化 发生变化之后 先执行重新编译html任务,然后执行刷新浏览器页面任务reload
gulp.watch("src/**/*.html", gulp.series(["html", "reload"]));
});
// 5 刷新页面
gulp.task("reload", done => {
browserSync.reload();
done();
});- 执行任务
gulp serve8. gulp-uglify
网站发布上线了需要将 开发环境中的 js,丑化 ,变成 人眼不怎么容易看懂的版本,提高安全性。如去掉注释,修改变量名,函数名等等。
- 安装
npm install gulp-uglify -D- 编写任务
const gulp = require("gulp");
const del = require("del");
const uglify = require("gulp-uglify");
// 1 引入包
const babel = require("gulp-babel");
// 1 引入包
gulp.task("js", () => {
return (
gulp
.src("src/js/*.js")
// 2 先使用babel将 js 编译为 es5
.pipe(babel())
.pipe(
// 3 执行函数
uglify({
// 3.1 丑化的等级
mangle: {
// 3.1.1 最高级
toplevel: true
}
})
)
.pipe(gulp.dest("./dist/js/"))
);
});- 执行任务
gulp js9. gulp-rev 和 gulp-rev-collector
一般的浏览器容易对前端的静态资源进行缓存,如 index.js index.css等。有时候 网站升级了,想让用户使用最新版本的js和css。 此时,可以在对应的静态资源上添加特定的字符,如 index2233355.js index20190108233410.css等。这个工作可以交由 gulp-rev和 gulp-rev-collector 完成
- gulp-rev 负责 给静态资源添加唯一后缀,俗称指纹。
- gulp-rev-collector 负责将 html中的 引用路径(
index.css) 改为(index392938098094.css)
- 安装
npm install gulp-rev gulp-rev-collector -D- 编写任务
const gulp = require("gulp");
const babel = require("gulp-babel");
const sass = require("gulp-sass");
sass.compiler = require("node-sass");
// 1 引入包
const rev = require("gulp-rev");
// 1 引入包
const revCollector = require("gulp-rev-collector");
// 2 处理sass
gulp.task("css", () => {
return (
gulp
.src("src/css/*.scss")
.pipe(sass())
// 2.1 给css文件添加指纹
.pipe(rev())
// 2.2 存放css
.pipe(gulp.dest("./dist/css/"))
// 3 将 css文件和css指纹文件的映射关系写到文件中
.pipe(
rev.manifest({
path: "rev-css-mainfest.json"
})
)
// 4 存入起来,给后面html修改引用使用
.pipe(gulp.dest("./src/rev/"))
);
});
// 2 处理js
gulp.task("js", () => {
return (
gulp
.src("src/js/*.js")
.pipe(babel())
// 2.1 给js文件添加指纹
.pipe(rev())
// 2.2 存放js文件
.pipe(gulp.dest("./dist/js/"))
// 3 将 js文件和js指纹文件的映射关系写到文件中
.pipe(
rev.manifest({
path: "rev-js-mainfest.json"
})
)
// 4 存入起来,给后面html修改引用使用
.pipe(gulp.dest("./src/rev/"))
);
});
// 3 处理html
gulp.task("html", () => {
return (
gulp
// 3.1 获取标签文件 和 指纹映射文件
.src(["src/index.html", "./src/rev/*.json"])
// 3.2 开始修改html中的文件引用
.pipe(revCollector())
// 3.3 存放我们的页面文件
.pipe(gulp.dest("dist/"))
);
});
// 4 按顺序执行
gulp.task("default", gulp.series(["css", "js", "html"]));- 执行任务
gulp开发环境下需要处理的任务
- 编译
sass文件 - 给
css文件添加浏览器前缀 - 给
css文件和js文件添加map文件映射 - 编译
js文件 - 实现
html标签组件 - 浏览器自动刷新
生产环境下需要处理的任务
- 编译
sass文件 - 给
css文件添加浏览器前缀 - 压缩和丑化
css文件 - 编译
js文件 - 压缩和丑化
js文件 - 实现
html标签组件 - 给资源文件添加指纹
开发环境相应配置
const del = require("del");
const gulp = require("gulp");
const sass = require("gulp-sass");
sass.compiler = require("node-sass");
const sourcemaps = require("gulp-sourcemaps");
const autoprefixer = require("gulp-autoprefixer");
const babel = require("gulp-babel");
const fileInclude = require("gulp-file-include");
const browserSync = require("browser-sync");
gulp.task("del", () => {
return del(["dist"]);
});
gulp.task("css", () => {
return gulp
.src("src/css/*.scss")
.pipe(sourcemaps.init())
.pipe(sass())
.pipe(
autoprefixer({
browsers: ["last 2 versions"]
})
)
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("dist/css/"));
});
gulp.task("js", () => {
return gulp
.src("src/js/*.js")
.pipe(sourcemaps.init())
.pipe(babel())
.pipe(sourcemaps.write("."))
.pipe(gulp.dest("dist/js/"));
});
gulp.task("copy", () => {
gulp.src("src/lib/**").pipe(gulp.dest("dist/lib/"));
return gulp.src("src/static/**").pipe(gulp.dest("dist/static/"));
});
gulp.task("html", () => {
gulp
.src("src/index.html")
.pipe(
fileInclude({
prefix: "@@",
basepath: "src/components/",
context: {
baseSrc: "."
}
})
)
.pipe(gulp.dest("dist/"));
return gulp
.src("src/pages/*.html")
.pipe(
fileInclude({
prefix: "@@",
basepath: "src/components/",
context: {
baseSrc: "."
}
})
)
.pipe(gulp.dest("dist/pages/"));
});
gulp.task("serve", () => {
browserSync({
server: {
baseDir: "dist",
port: 8080
},
notify: false
});
gulp.watch("src/css/*.scss", gulp.series(["css", "reload"]));
gulp.watch("src/**/*.html", gulp.series(["html", "reload"]));
gulp.watch("src/js/*.js", gulp.series(["js", "reload"]));
gulp.watch(["src/lib/**", "src/static/**"], gulp.series(["copy", "reload"]));
});
gulp.task("reload", done => {
browserSync.reload();
done();
});
gulp.task(
"default",
gulp.series(["del", "css", "js", "copy", "html", "serve"])
);生产环境相应配置
const del = require('del');
const gulp = require('gulp');
const sass = require('gulp-sass');
sass.compiler = require('node-sass');
const autoprefixer = require('gulp-autoprefixer');
const babel = require('gulp-babel');
const uglify = require('gulp-uglify');
const fileInclude = require("gulp-file-include");
const rev = require("gulp-rev");
const revCollector = require("gulp-rev-collector");
gulp.task("del", () => {
return del(['dist']);
});
gulp.task("css", () => {
return gulp.src('src/css/*.scss')
.pipe(sass({
outputStyle: 'compressed'
}))
.pipe(autoprefixer({
browsers: ['last 2 versions']
}))
.pipe(rev())
.pipe(gulp.dest("./dist/css/"))
.pipe(rev.manifest({
path: "rev-css-mainfest.json"
}))
.pipe(gulp.dest("./src/rev/"));
});
gulp.task('js', () => {
return gulp.src('src/js/*.js')
.pipe(babel())
.pipe(uglify(
{ mangle: {
toplevel: true
}}
))
.pipe(rev())
.pipe(gulp.dest("./dist/js/"))
.pipe(rev.manifest({
path: "rev-js-mainfest.json"
}))
.pipe(gulp.dest("./src/rev/"));
});
gulp.task("copy", () => {
gulp.src("src/lib/**")
.pipe(gulp.dest("dist/lib/"));
return gulp.src("src/static/**")
.pipe(gulp.dest("dist/static/"));
});
gulp.task("html", () => {
gulp.src(['src/index.html','./src/rev/*.json'])
.pipe(fileInclude({
prefix: '@@',
basepath: 'src/components/',
context: {
baseSrc: "."
}
}))
.pipe(revCollector())
.pipe(gulp.dest('dist/'));
return gulp.src(['src/pages/*.html','./src/rev/*.json'])
.pipe(fileInclude({
prefix: '@@',
basepath: 'src/components/',
context: {
baseSrc: ".."
}
}))
.pipe(revCollector())
.pipe(gulp.dest('dist/pages/'));
});
gulp.task("default", gulp.series([
'del',
'css',
'js',
'copy',
'html'
]));