使用 gulp 压缩 Hexo 博客文件(兼容 ES6 标准)

使用文本编辑器打开 Hexo 生成的博客文件,往往会发现其中存在大量的空格与空行,这虽然不影响代码发挥作用,但却会在一定程度上增加文件的大小。

实际上不止空白,这些由 Hexo 生成的文件中还有很多能够被优化以减小大小的地方,而要提高网站访问速度,减小资源文件的大小一直是最有效的手段之一。

gulp 是一个自动化构建工具,一般用于开发过程中执行一些常见任务,它有很多社区提供的强大插件可供使用,极大的简化了任务处理流程。在这里我们用它来对 Hexo 生成的博客文件进行压缩优化处理。

其他教程存在的问题

使用关键词 hexo gulp 在网上搜索,可以搜到一堆类似的教程,但是根据我的实际测试,网上搜到的这些教程大部分都已经过时了,现在再使用的话或多或少的存在一些问题。

这些教程中一般都是通过安装 gulp-minify-cssgulp-uglifygulp-htmlcleangulp-htmlmin 这几个插件来处理的。下面按照压缩任务划分,分别说明一下现在还按照这些教程操作的话存在的一些问题。

压缩 CSS 的问题

上面那几个插件中 gulp-minify-css 是用来压缩 CSS 代码的,使用命令 npm install gulp-minify-css 安装它,此时会发现在该命令的输出中存在如下的一行:

1
npm WARN deprecated gulp-minify-css@1.2.4: Please use gulp-clean-css

说得很明显了,这个插件已弃用,请使用 gulp-clean-css 。这虽然并不影响我们的正常使用该插件,但是有更好的替代品的话为什么还要用这个已弃用的插件呢?

压缩 JS 的问题

网上的大部分教程都是使用 gulp-uglify 来压缩 JS 代码,然而这个插件不兼容 JS 的 ES6 标准,导致在我的实际测试中(Hexo 5.x、NexT 8.x)使用该插件时出现了报错,如下所示,最后直接是“无法压缩 JavaScript”:

1
2
3
4
[19:31:26] 'minify-js' errored after 489 ms
[19:31:26] GulpUglifyError: unable to minify JavaScript
Caused by: SyntaxError: Unexpected token: punc «)»
File: C:\Users\Administrator\Desktop\hexo\new-blog\public\js\local-search.js

ES6 标准在2015年6月就正式通过了,现在已经过去了这么久,很多地方都有在使用,而 gulp-uglify 这个插件却完全不兼容,这无疑是个问题。

压缩 HTML 的问题

上面提到的插件中 gulp-htmlcleangulp-htmlmin 是用来压缩 HTML 代码的。

网上教程的一般做法是先将代码传递给 gulp-htmlclean 清理掉其中的空白,然后再传递给 gulp-htmlmin 来移除注释、压缩 HTML 文件中的 CSS、JS 代码等。然而查看 gulp-htmlmin 所基于的 html-minifier文档发现,它有一个 collapseWhitespace 参数,设置为 true 时可以移除 HTML 代码中的空白块,那还多此一举的安装一个 gulp-htmlclean 插件干什么呢?

另外,上面提到了 gulp-htmlmin 可以压缩 HTML 中的 JS 代码,这个功能用的是跟 gulp-uglify 一样的底层库 uglify-js 来实现的,这也就导致它同样的不兼容 ES6 标准。最终会发现 HTML 文件中的内容并没有被全部压缩成“一行”,仍有部分 JS 代码是以未被压缩的形式存在的。

我的解决办法

针对上面那些问题,在一番查找资料与实际测试后,最终还是找到了一些在我看来比较完美的解决办法:

  • 压缩 CSS: 这个是最简单的,按照它的提示换成 gulp-clean-css 这个插件就行了。
  • 压缩 JS: 针对这个问题网上有一种在我看来比较“邪教”的做法:使用 babel 将 ES6 标准的代码编译为 ES5 标准的代码然后再继续使用 gulp-uglify 进行压缩。怎么说呢,这样做确实是可行的,但就是看着有种不爽的感觉。经过搜索,最后找到了 gulp-uglify-es 这个插件,它将底层库替换成了 terser,可以完美支持 ES6 标准。
  • 压缩 HTML: 同样要解决对 ES6 标准支持的问题,最终换到了 gulp-html-minifier-terser 这个插件,它是 gulp-htmlmin 的 fork,但是将底层库换成了 html-minifier-terserhtml-minifier 的 fork,将压缩 JS 代码的功能修改为了使用 terser 库处理)。其次就是不再使用 gulp-htmlclean 插件,改为在使用 gulp-html-minifier-terser 插件时传入参数 collapseWhitespace: true

操作方法及任务配置

根据 gulp 及各个插件的文档,我们首先需要全局安装 gulp-cli,然后在博客工作目录下安装需要的插件:

1
2
npm install --global gulp-cli
npm install gulp gulp-clean-css gulp-uglify-es gulp-html-minifier-terser

安装完成后在博客工作目录下新建文件 gulpfile.js ,写入如下 gulp 任务配置代码(详细描述见注释):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
const gulp = require('gulp');
const cleancss = require('gulp-clean-css');
const uglify = require('gulp-uglify-es').default;
const htmlmin = require('gulp-html-minifier-terser');


// 压缩public目录下的css文件
// 可接受参数的文档:https://github.com/jakubpawlowicz/clean-css#constructor-options
gulp.task('minify-css', () => {
return gulp.src('./public/**/*.css') // 处理public目录下所有的css文件,下同
.pipe(cleancss({ compatibility: 'ie8' })) // 兼容到IE8
.pipe(gulp.dest('./public'));
});

// 压缩public目录下的js文件
gulp.task('minify-js', () => {
return gulp.src('./public/**/*.js')
.pipe(uglify())
.pipe(gulp.dest('./public'));
});

// 压缩public目录下的html文件
// 可接受参数的文档:https://github.com/terser/html-minifier-terser#options-quick-reference
gulp.task('minify-html', () => {
return gulp.src('./public/**/*.html')
.pipe(htmlmin({
removeComments: true, // 移除注释
removeEmptyAttributes: true, // 移除值为空的参数
removeRedundantAttributes: true, // 移除值跟默认值匹配的属性
collapseBooleanAttributes: true, // 省略布尔属性的值
collapseWhitespace: true, // 移除空格和空行
minifyCSS: true, // 压缩HTML中的CSS
minifyJS: true, // 压缩HTML中的JS
minifyURLs: true // 压缩HTML中的链接
}))
.pipe(gulp.dest('./public'))
});

// 默认任务,不带任务名运行gulp时执行的任务
gulp.task('default', gulp.parallel(
'minify-css', 'minify-js', 'minify-html'
));

保存之后先用 hexo g 生成博客文件,然后执行命令 gulp 就可以对刚刚生成的博客文件(public 目录下的文件)进行压缩优化处理了。