这是我参与更文挑战的第15天,活动详情查看: 更文挑战
前言
在上一篇文章里,已经对 gulp 的任务、读取文件和输出文件、管道做了一个介绍,在这篇文章里将会介绍如何很好地管理 html。
压缩 html 代码
gulp-htmlmin 是 gulp 的一个压缩 html 的插件,下面介绍 gulp-htmlmin 的用法。
运行以下命令进行安装
npm i -D gulp-htmlmin
修改 gulpfile.js 的配置
const { series, parallel, src, dest } = require('gulp')
const htmlmin = require('gulp-htmlmin')
function html() {
return src('src/**/*.html')
.pipe(htmlmin({
removeComments: true, //清除HTML注释
collapseWhitespace: true, //压缩HTML
collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input />
removeEmptyAttributes: true, //删除所有空格作属性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: true, //删除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: true, //删除<style>和<link>的type="text/css"
minifyJS: true, //压缩页面JS
minifyCSS: true //压缩页面CSS
}))
.pipe(dest('dist'))
}
exports.build = series(html)
在上一篇文章里,已经在 src 写了 index.html,内容如下。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
</head>
<body>
</body>
</html>
为了方便以及统一,我们先在 package.json 写上构建的快捷命令,使用 npm run build
来代替 gulp build
。
{
...
"scripts": {
...
"build": "gulp build",
},
}
运行构建命令 npm run build
我们可以看到 dist 目录下的 index.html 被压缩了。
复用模板
gulp-file-include 的作用是将指定的 html 文件的代码复制到一个 html 文件上,比如:所有页面都需要有一个相同的头部和脚部,如果在每个页面上都写一次头部和脚部,那代码就显得很冗余,使用 gulp-file-include 可以将头部和脚部的代码从主页面上分离出来。
安装
npm i -D gulp-file-include
gulpfile.js 配置
...
const fileinclude = require('gulp-file-include')
function html() {
return src(['src/**/*.html', '!src/include/**.html'])
.pipe(fileinclude({
prefix: '@@', //引用符号
basepath: './src/include' //引用文件路径
}))
.pipe(htmlmin({
removeComments: true, //清除HTML注释
collapseWhitespace: true, //压缩HTML
collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input />
removeEmptyAttributes: true, //删除所有空格作属性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: true, //删除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: true, //删除<style>和<link>的type="text/css"
minifyJS: true, //压缩页面JS
minifyCSS: true //压缩页面CSS
}))
.pipe(dest('dist'))
}
注意:
- 在 gulpfile.js 配置里,
src
方法的参数改变成数组了,意思是处理 src 目录里的所有 html 文件,但是不处理 src/include 里的 html 文件。因为 include 文件夹里的文件就是 “组件”,用来被引入到 html 去。 - fileinclude 要写在 htmlmin 之前,要全部代码引入到 html 后,再压缩。
在 src 目录里创建一个 include 文件夹,里面创建一个 header.html,一个 footer.html,里面写如下代码。
header.html
<div>头部</div>
footer.html
<div>脚部</div>
header.html 和 footer.html 不需要有 html 、body 等标签,记得他们里面的内容是要被 index.html 引入的。
在 index.html 使用 @@ 将头部和脚部引入。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>首页</title>
</head>
<body>
@@include('./header.html')
<div>首页内容</div>
@@include('./footer.html')
</body>
</html>
运行 npm run build
命令后,我们可以发现 dist/index.html 里面多出了头部和脚部的相关代码。
到了这里,html 就已经处理好了,但是现在的项目并不够好,没有优化打包过程,也没有像 webpack 那样的 devServer 可以用来快速开发网站,我们可以继续添加以下插件完善项目。
优化编译过程
changed 是一个只让更改过的文件通过管道的插件,它可以防止没有更改过的文件重复编译,以此提高效率。
安装
npm i -D gulp-changed
gulpfile.js
...
const changed = require('gulp-changed')
function html() {
return src(['src/**/*.html', '!src/include/**.html'])
.pipe(changed('dist'))
.pipe(fileinclude({
prefix: '@@', //引用符号
basepath: './src/include' //引用文件路径
}))
.pipe(htmlmin({
removeComments: true, //清除HTML注释
collapseWhitespace: true, //压缩HTML
collapseBooleanAttributes: true, //省略布尔属性的值 <input checked="true"/> ==> <input />
removeEmptyAttributes: true, //删除所有空格作属性值 <input id="" /> ==> <input />
removeScriptTypeAttributes: true, //删除<script>的type="text/javascript"
removeStyleLinkTypeAttributes: true, //删除<style>和<link>的type="text/css"
minifyJS: true, //压缩页面JS
minifyCSS: true //压缩页面CSS
}))
.pipe(dest('dist'))
}
changed 需要提前知道目标目录位置,才能知道哪些文件没有被更改过,所以 changed 里面的入参是 dist 路径。
changed 不单止可以用于管理 html,当然也可以管理其他资源,后面文章也会用到它。
本地服务器
gulp-webserver 是一个本地服务器,具有热替换、代理等功能,使用它可以更快捷开发程序。
安装
npm i -D gulp-webserver
gulpfile.js
...
const webserver = require('gulp-webserver')
...
function devServer() {
return src('dist').pipe(webserver({
port: 3000,
livereload: true, // 是否实时加载
// directoryListing: true, // 是否开启浏览目录
// open: true, // 是否自动打开
// proxies: [ // 代理,可以用来解决跨域问题
// {source: '/api', target: 'http://xxxx.com', options: {headers: {"Content-Type": 'application/x-www-form-urlencoded'}}}
// ]
}))
}
exports.default = series(html, devServer) // 新增这条命令
exports.build = series(html)
同样地,为了方便和统一,在 package.json 添加开发快捷命令。
{
...
"scripts": {
...
"dev": "gulp"
},
...
}
运行 npm run dev
,在浏览器输入 localhost:3000,即可看到我们的编译后的内容。
但是如果我们更改 src/index.html 里面的内容,似乎浏览器并没有自动加载新内容,那是因为我们没有重新编译代码到 dist 目录,如果我们更改 dist/index.html 的内容,我们可以发现浏览器会自动更新内容。那么如何去监测 src 里的内容呢?
这里用到 gulp 的 watch 方法。
新增一个 watch 来监听 src 目录的 html 文件,如果 html 文件有更改,则重新执行 html 任务。
const { series, parallel, src, dest, watch } = require('gulp')
...
function watcher() {
watch('src/**/*.html', series(html))
}
exports.default = series(html, devServer, watcher)
...
这个时候再执行 npm run dev
,可以发现改变 src/index.html 可以触发浏览器刷新。
gulp-webserver 还可以写代理来解决跨域问题,上面的代码已经贴出来,把注释去掉,修改一下值即可使用,在这里不详细讲述如何使用。
注意:include 文件夹里的 html 内容更改并不会刷新浏览器,一开始我以为是 src(['src/**/*.html', '!src/include/**.html'])
里的 '!src/include/**.html'
的影响,但是后来我删掉了,也没用。我们只能通过删除 index.html 的 @@include 后保存,再添加回去保存来起到手动刷新作用,又或者重新运行 npm run dev
。我找不到这个问题所在,也许是插件的问题,知道的小伙伴可以在评论区告诉我一下。
删除旧文件
每次编译前,dist 的旧文件不会自动删除,因此我们每次都要手动删除 dist 目录,防止有旧文件的存在,但是这样会很麻烦,我们可以通过 del 插件和 gulp 的 watch 来实现自动删除文件功能。
安装
npm i -D del
gulpfile.js
const del = require('del')
...
function clean() {
return del('dist')
}
exports.default = series(clean, html, devServer, watcher)
exports.build = series(clean, html)
当我们每次运行 npm run build
或者 npm run dev
时,程序都会事先删除 dist 目录。
但是到了这里还不完整,如果你在 npm run dev
时,中途删除 src 的源码文件,可能会导致 dist 还会遗留这个文件。
你可以试试在运行 npm run dev
的情况下, src 里新建一个 aa.html 文件,dist 里面会打包出一个 aa.html 文件,然后你删掉 src/aa.html,你会发现 dist 里还是存在 aa.html 文件。
为了解决这个问题,我们需要修改一下 watcher。
gulpfile.js
const Path = require('path')
function watcher() {
watch('src/**/*.html', series(html)).on('unlink', function (path) {
del('dist/**/' + Path.basename(path))
})
}
这个代码的意思是,监听 html 的监听器监听“删除”事件,当 html 文件被删除时,dist 里的对应 html 文件也被删除。
完整项目
2021.8.30,我重新整理了一遍项目,已放到 gitee 上,大家可以 clone 下来直接用,代码的提交记录顺序和我这个系列文章教程顺序是一致的,大家看到哪一篇文章时,就回滚代码到哪一个版本,这样看项目代码会更直观。
gitee 库链接:gitee.com/only1zhuo/g…