最近使用lighthouse对博客做了一个测试,测试结果如下,以下是桌面 PC 端的测试的结果:

下图是一个优秀个人博客网站的测试结果,通过对比可以发现有很大差距。

这个测试能够一定程度反映网站的用户体验,测试主要包含性能,可访问性,SEO和最佳实践四个方面。通过测试,我们能发现网站存在的问题, 同时lighthouse工具也提供关于这些问题的一些改进建议。其中很多问题网上已经有优化方案了,我们就不再搬运了,但是关于Hexo建站如何优雅使用webp图片格式的问题, 还没有成熟的方案,本片博文将给大家分享我是如何实现 Hexo 兼容webp格式图片,且做到无感知,全自动化的管理的; 同时也会简单介绍通过将博客迁移到香港云主机,优化国内读者的访问速度的过程。

图片资源优化

技术类文章不可避免地需要大量的配图,同时随着博客文章的图片的增多,偶尔出现几 M 大小的图片,博客页面加载就会变慢,影响读者的阅读体验。 缩小页面的中配图的大小,加速博文渲染速度迫在眉睫,但是最终实现不能以牺牲图片的质量和显示效果为代价。查阅相关资料,我尝试了从以下两种思路进行优化。

第一种思路是使用压缩工具将过大的图片压缩,目前有两种类型的工具,一种是以TinyPNG为代表的在线工具, 这类工具最大的缺点是对后续流程自动化不太友好(也可以通过selenium这类工具实现),不过TinyPNG提供了API接口,还提供了常用语言的客户端。 另一种是以OptiPNG和Jpegtopnm为代表的本地命令行工具,缺点是每个工具只支持部分格式的图片,没有一个支持多种类型的工具, 同时由于压缩算法需要大量的算力,本地压缩一张图片会消耗很多资源(时间和 CPU)。TinyPNG借助服务器相对来说速度要快一些。 其优点是使用这类工具对后续自动化处理十分友好。

另一种思路是转换图片格式,本质上也是压缩,lighthouse提供的建议是使用JPEG 2000, JPEG XR, and WebP这几种格式。 后续只会介绍webp格式,其他两种有需要自行了解。 webp是 Google 推出的现代图片格式,支持无损和有损压缩,旨在减小网站的图片的体积,提高网站的速度。使用方式十分简单,通过下载命令行工具cwebp进行转换:

1
2
3
# 具体使用方式参考使用文档
➜ bin brew install webp
➜ bin cwebp 2020-06-04-11-33-22.png -o 2020-06-04-11-33-22-new.webp

以下是使用TinyPngOptiPNGwebp处理所得到的图片大小的对比(测试结果有所差异):

通过对比,webp格式的效果最好,而且通过对比几张图片,显示效果并没有明显的差别。毫无疑问,webp是更好的方案。 webp是较新的技术,所以一些浏览器可能还没有支持。 测试以下,果然主流的Safari不支持。这意味者使用safara访问时,仍然需要访问PNG这类格式的图片。 而使用支持webp的浏览器,则可以访问webp格式的图片。

Hexo要实现浏览器的兼容,有两种方式,一种云端处理,这种方式博客无需任何变化,转化借助 CDN 或者特定服务实现,例如, CloudFlare的 Pro 用户可以通过开启Polish实现。如果你的图片部署在云主机上,同时博客中的图片保存在本地(没有通过外部引用), 你可以部署webp_server_go服务实现转换。 另一种方式相对来说比较简单,通过一段Javascript脚本判断浏览器是否支持webp格式,如果支持则获取webp格式图片, 否则获取原格式图片,前提需要在图片服务上保存两种类型的图片。由于博主的图片都是通过Jsdelivr访问的,如果使用webp_server_go做一道中转, 比较浪费流量和性能。所以就采用脚本方式实现webp浏览器兼容。以下是改造 Hexo Butterfly 主题实现自动转换的过程,其他主题类似:

首先在_config.yaml定义变量控制是否需要转换webp

1
2
## webp
use_webp: tru

在目录themes/Butterfly/scripts添加一个目录webp,并创建index.js文件:

1
2
3
4
5
6
7
8
"use strict";

if (hexo.config.use_webp) {
hexo.extend.filter.register(
"after_render:html",
require("./lib/process").webpProcess
);
}

继续在webp目录创建子目录lib,并创建process.js文件:

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
"use strict";

const fs = require("hexo-fs");

function webpProcess(htmlContent) {
return htmlContent.replace(
/<img(.*?)src="(.*?)"(.*?)>/gi,
function (str, p1, p2) {
if (
/https:\/\/cdn.jsdelivr.net\/gh\/donggangcj\/CDN\/image\/(.*?)\.(jpg|jpeg|png)/gi.test(
p2
)
) {
return `<picture><source srcset="${p2.replace(
/\.(jpg|jpeg|png)/gi,
".webp"
)}" type="image/webp">${str}</picture>`;
}
return str;
}
);
}

module.exports.webpProcess = function (htmlContent) {
return webpProcess.call(this, htmlContent);
};

注意修改你的图片服务地址,上述脚本逻辑主要是查询页面中的图片引用,并使用<picture></picture>标记进行替换, 该标记可以使用多个<source>元素和一个<img>标记。将WebP格式文件放入<source>元素中,并将应用更加广泛的JPEG/PNG等传统格式文件放入<img>标记中。 对于能够理解image/webp源的浏览器会加载<source>标记内的WebP格式文件,而不理解的浏览器则回退至<img>标记内的传统格式文件。

这样就已经完成了吗?🤪 当然不是啦!思考一下到现在为止,博客图片管理流程是什么样子?

熟悉我的读者应该知道我的博客已经通过命令行工具hexo-iamge-sync(自己通过 python 开发的命令行工具,现在已经通过 golang 重构)实现了Copy-And-Paste的方式, 但是为了缩小图片的大小,又多了手动压缩,转换 webp 的处理,这些步骤是繁琐的且需要频繁操作,完全可以被自动化。当然Let's SMTC(show me the code),来看下面的一段操作:

上述操作包含两步,首先查看未同步到jsdelivr的图片,然后将图片发布到jsdeliver,当然也可以通过flag控制一些选项,例如是否对所有图片重新压缩和转换, 这对更新操作和删除无用图片十分有帮助。该工具目前还处于开发阶段,代码仓库地址为hack。 需要的读者可以直接使用,当然也可以自己开发工具,简化这些繁琐的工作流。

博客迁移到香港云主机

由于我的博客目前的受众主要是国内的读者,但是Github Page在国内的访问速度实在有点慢,这就导致我向别人安利自己的博客时, 别人要么打不开要么得加载 10s 以上,这就非常尴尬。具体国内的访问延迟测试如下:

所以优化国内的访问速度同样迫在眉睫,我尝试了以下几种优化方式:

  1. 使用CloudFlare做全站CDN加速,如果是Pro用户,还可以使用Polish功能,在云端对图片进行 webp 的转码, 但是最终我还是放弃了此方案,主要是针对国内的用户,仍然需要备案,免费的加速效果并不明显;
  2. 国内上云,需要备案就暂时不考虑了;
  3. 使用ZEIT,大陆访问ZEIT是最快的! 比 Netlify 和 Github Pages 以及 Heroku 都快。注意线路问题,电信走香港、台湾线路,联通移动会绕美国。 同时使用其Serverless功能可以实现很多有意思的功能。这种方式资源有限,且不方便部署和后续迁移;
  4. 托管到国内访问速度良好的 VPS 上(VPS 服务提供商的选择很重要,通常选择香港和台湾主机)。该方式优点自主可控,同时也很灵活,如果 VPS 选的合理, 速度相对来说也是最快的,但是这一切的代价就是 💰;

综合考虑,最终选择通过部署到 VPS 上来优化国内访问速度。部署过程十分简单,主要是将博客的静态文件同步到云主机指定目录,再使用 Nginx 代理即 OK,当然,配置Https 也必不可少; hexo支持部署到多个托管服务上,所以笔者同时将博客部署到github page和云主机上。

测试迁移后效果,国内提速十分明显:

插曲:在迁移的过程中,也试了Nova Kwok’s Awesome Blog的方案,直接使用 Nova 提供的主机, 这个速度简直太顺滑,不过目前自己还能折腾,就没有使用这个方案。

Google 搜索引擎

Google的搜索引擎爬虫爬取需要一定时间,而我的博客刚换了域名,所以使用Google Search Console工具手动推了sitemap

  1. 步骤一:生成sitemap文件,
1
2
3
4
5
# 安装sitemap生成插件
➜ blog-new git:(master) npm install hexo-generator-sitemap --save

# 生成博客静态文件(注意_config.yaml中博客地址需要与实际部署地址一致)
➜ public git:(master) ✗ hexo g && hexo d
  1. 步骤二:前往Google SearchConsole验证网站是否属于本人。这里需要在 DNS 中添加一条TXT记录。验证通常很快就会通过。

通过在浏览器搜索site:blog.happyhack.io验证站点是否被 Google 引擎索引。

关于博客的 SEO 优化,笔者还在学习,博客也刚刚起步,后续有机会再和大家分享学习。

一句话

  1. 为博客添加高质量动图:通过stories生成动态插图并嵌入博客中。

总结

这是博客建站系列的第五篇,主要分享这段时间对博客的一些优化工作,主要契机是通过lighthouse测试发现博客站点有很多不足, 从而进行的一系列优化,其中很多优化工作,我没在本片博文中介绍,主要是因为这些优化工作比较琐碎,同时优化方案也容易找到, 对于刚建立的博客的读者应该有一定的参考意义。这段时间,认真整理博客才发现,博客的建站和优秀博文的创作不是一件容易的事, 同时对那些维护了优秀博客的博主深感敬意,尤其是在这个信息快餐时代。最后,博客是一个能够让我深度思考的地方, 希望我的博文能够被更多地人阅读,并给读者带来一些帮助和灵感。

参考

  1. hexo 博客建站方式对比
  2. How to Get Your Hexo Blog Listed/Indexed on Google
  3. Hexo 博客提交百度、谷歌搜索引擎收录
  4. hexo 实现 webp 支持