相信不少小伙伴都在使用 GitHub Pages 提供的免费静态网站托管来搭建自己的博客,但是因为墙的存在和特殊国情,使用 GitHub Pages 搭建的网站速度普遍不快,因此很多小伙伴只能转战国内付费的服务器和 CDN。
正巧我也在使用 GitHub Pages 搭建自己的静态博客,正好来说一下我的优化方法。
默认情况下,如果我们查看 Hexo 生成的静态网页源代码,会发现存在大量的空格、空行、注释等无用内容。同样的,如果使用的 hexo 主题没有进行优化,大量的 css 和 js 文件也存在这样的垃圾内容。
如果你在一些大型网站右键查看网页源代码,你会发现他们的 html\js\css 是经过压缩处理的,没有多余的换行和注释,这势必会节省带宽流量和传输时间,提升用户体验。
所以我们优化速度的第一关就是对 Hexo 生成的代码进行压缩。
这里我使用的工具是 gulp
在自己本机安装
为了 GitHub Action 或其他 CI\CD 平台也能够进行安装,这里推荐
1
| npm install gulp --save-dev
|
我们还需要一些依赖
1
2
3
4
5
6
7
8
9
10
11
| npm install --save-dev \
gulp-minify-css \
gulp-babel \
gulp-uglify \
gulp-htmlmin \
gulp-htmlclean \
gulp-imagemin \
imagemin-jpegtran \
imagemin-svgo \
imagemin-gifsicle \
imagemin-optipng
|
在博客 hexo 的根目录下,新建 gulpfile.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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
| var gulp = require("gulp");
var minifycss = require("gulp-minify-css");
var uglify = require("gulp-uglify");
var htmlmin = require("gulp-htmlmin");
var htmlclean = require("gulp-htmlclean");
var imagemin = require("gulp-imagemin");
// 压缩css文件
gulp.task("minify-css", function () {
return gulp
.src("./public/**/*.css")
.pipe(minifycss())
.pipe(gulp.dest("./public"));
});
// 压缩html
gulp.task("minify-html", function () {
return gulp
.src("./public/**/*.html")
.pipe(htmlclean())
.pipe(
htmlmin({
collapseWhitespace: true,
collapseBooleanAttributes: true,
removeComments: true,
removeEmptyAttributes: true,
removeScriptTypeAttributes: true,
removeStyleLinkTypeAttributes: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
ignoreCustomFragments: [/\{\{[\s\S]*?\}\}/],
})
)
.pipe(gulp.dest("./public"));
});
// 压缩js文件
gulp.task("minify-js", function () {
return gulp
.src(["./public/**/*.js", "!./public/js/**/*min.js"])
.pipe(uglify())
.pipe(gulp.dest("./public"));
});
// 压缩图片
gulp.task("minify-images", function () {
return gulp
.src([
"./public/**/*.png",
"./public/**/*.jpg",
"./public/**/*.gif",
"./public/**/*.svg",
])
.pipe(
imagemin([
imagemin.gifsicle({ interlaced: true }),
imagemin.mozjpeg({ quality: 75, progressive: true }),
imagemin.optipng({ optimizationLevel: 5 }),
imagemin.svgo({
plugins: [{ removeViewBox: true }, { cleanupIDs: false }],
}),
])
)
.pipe(gulp.dest("./public"));
});
gulp.task(
"default",
gulp.series(
gulp.parallel("minify-html", "minify-css", "minify-js", "minify-images")
)
);
|
在使用 hexo g
生成静态网站后, 运行 gulp
进行压缩
如果你查看博客的网络请求内容,你会发现在 html 加载之后,还有一堆小文件等待加载,而这些 css\js\图片文件的加载占据了大部分的网页打开时间。
因为 GitHub Pages 的延迟巨大,速度极慢,我们更有必要使用国内的 CDN 对这些资源进行分发。
不想使用国内付费的 CDN 服务,我尝试过使用 CloudFlare 进行加速(实质减速)效果不佳,后来发现了 jsDelivr。
jsDelivr 是一家开源免费 CDN,主要是对 npm 包进行 CDN 分发
绝妙的是它还能对 GitHub 和 Wordpress 进行 CDN 分发
我们可以借助 jsDelivr 的 GitHub 资源分发 服务来对我们博客中的 css\js\小图片进行加速
这是我目前找到的唯一一家在国内有节点并且不需要备案的 CDN 分发服务
这里我就以我使用的主题为例,分享一下我如何使用 jsDelivr 进行 CDN 分发
jsDelivr 针对 GitHub 资源有众多 URL 格式
1
2
3
4
5
6
7
| https://cdn.jsdelivr.net/gh/user/repo@version/file
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery@3/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/src/core.min.js
https://cdn.jsdelivr.net/gh/jquery/jquery/
|
考虑到 jsDelivr 默认缓存时间是 7 天,如果我们想要修改实时生效而不需要等到缓存过期,最适合的是
1
2
3
| https://cdn.jsdelivr.net/gh/jquery/jquery@3.2.1/dist/jquery.min.js
https://cdn.jsdelivr.net/gh/ github用户名 / 库名 @ 版本号或者tag / 路径/文件名
|
我们可以通过打 tag 来访问同一个资源文件的不同版本,而不需要考虑缓存时间
大部分 hexo 主题并不会对使用到的 js\css\图片\字体 套上 CDN,我们来手动替换
大部分 css 样式会在 head
标签里面引入,这里的 css 样式表会阻塞页面的渲染,导致打开慢的体验,所以需要特别注意
我将我使用的主题的 style.css \ rtl.css \ disquesjs.css 替换成 jsDelivr,明显提升了等待时间
还有一些其他地方的 css 引入
寻找并替换各种调用到的 js 脚本
main.js
disqusjs.js
还有其他的一些地方,不一一列举了
字体需要特别注意,通常情况下比较大,耗时比较长
我使用的主题使用的字体通过 all.min.css
引入,因为前面这个 css 样式已经通过 jsDelivr 导入,里面的字体使用的是相对链接,所以字体默认也是通过 jsDelivr 引入了
一般是 logo 等资源,根据主题自行替换
更新:为了更好的控制版本和决定是否使用 jsDelivr, 可以将这个地方独立出来放到配置文件里
_config.yml
1
2
3
| cdn:
enabled: true
url: https://cdn.jsdelivr.net/gh/zu1k/blog@0.0.1.2
|
用到的地方
1
2
3
4
5
6
7
8
| <!-- styles -->
<% if (theme.cdn.enabled) { %>
<link rel="stylesheet" href="<%= theme.cdn.url %>/css/style.css">
<% } else { %>
<%- css('css/style') %>
<% } %>
其他的地方同样的方法
|
无论怎样优化,字体加载的时间无法忽略,这段时间的网页文字显示为空,这给用户带来卡顿感
我们必须使字体加载时文字可见,这样才能弥补 github pages 的慢
具体方法是将各 @font-face
中 font-display
设置为 swap
, 这样可以在字体未加载完时临时使用系统字体替代,加载完后重新渲染字体
每一个地方都需要改,自己搜索吧
由于众所周知的原因,disqus 被墙了,国内访问不了,而大部分 hexo 网站都使用 disqus 作为评论系统,这导致网页会卡在评论区的加载上,虽然网页已经加载完了,但进度条还在进行,给用户带来慢的感觉。
并且,即使有的用户翻墙能够访问 Disqus,但 Disqus 本身非常笨重,各种 CSS/JS/Font/API 加起来请求不小于 2MB,当 Disqus 加载时,浏览器会在主线程中同步解析、渲染 Disqus,造成卡顿感。
在上网搜索之后,找到了一个替代方案,那就是苏卡卡大佬的 DisqusJS,大家可以根据教程对自己博客的主题进行修改
参考链接:
对于使用的 Disqus API 反代,我自己测试发现苏卡卡大佬提供的速度不太行,不知道是什么原因,所以推荐自己进行搭建,我是用的是 zeit 进行搭建,感觉还不错
如果 disqusJS 默认样式不适合自己的主题,推荐 fork 原库进行修改,注意要使用 1.2.6,最新的 master 在懒加载上有点问题
如果图片和评论区随着页面在一开始就加载,势必会拖累网页首次渲染和文字的迅速显示,这里最好的办法是使用懒加载技术
对于图片,我使用了 hexo-lazyload-image
这个插件
安装
1
| npm install hexo-lazyload-image --save
|
配置文件中添加
1
2
3
4
| lazyload:
enable: true
onlypost: false
loadingImg: https://cdn.jsdelivr.net/gh/zu1k/blog@0.0.1.2/images/loading.png
|
顺便给懒加载添加了 cdn 功能,可以替换成 cdn 链接来加速
1
| npm install hexo-lazyload-image-cdn --save
|
配置文件中添加
1
2
3
4
5
6
7
| lazyload:
enable: true
onlypost: false
loadingImg: # eg ./images/loading.gif
cdn:
enabled: false
url: https://cdn.com
|
对于评论区,很多情况下用户根本不会划到页面底部(文章写得太烂没人看得下去)。
所以我这里对 disqus 的加载使用懒加载技术,参考 https://blog.skk.moe/post/prevent-disqus-from-slowing-your-site/
我使用的是 disqusJS, 下面给出加载的 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
27
28
29
30
31
32
33
34
35
36
| <!-- DisqusJS Comments -->
<% if (theme.disqusjs.enabled && theme.disqusjs.shortname){ %>
<script crossorigin defer src="https://cdn.jsdelivr.net/gh/zu1k/DisqusJS@1.2.6.3/dist/disqus.js" id="disqusjs-script"></script>
<script>
document.getElementById("disqusjs-script").addEventListener("load",function() {
setTimeout(
function() {
function t() {
var dsqjs = new DisqusJS({
shortname: '<%= theme.disqusjs.shortname %>',
siteName: '<%= theme.disqusjs.siteName %>',
api: '<%= theme.disqusjs.api %>',
apikey: '<%= theme.disqusjs.apikey %>',
admin: '<%= theme.disqusjs.admin %>',
adminLabel: '<%= theme.disqusjs.adminLabel %>'
});
}
var runningOnBrowser = typeof window !== "undefined";
var isBot = runningOnBrowser && !("onscroll" in window) || typeof navigator !== "undefined" && /(gle|ing|ro|msn)bot|crawl|spider|yand|duckgo/i.test(navigator.userAgent);
var supportsIntersectionObserver = runningOnBrowser && "IntersectionObserver" in window;
if (!isBot && supportsIntersectionObserver) {
var disqus_observer = new IntersectionObserver(function(entries) {
if (entries[0].isIntersecting) {
t();
disqus_observer.disconnect();
}
}, { threshold: [0] });
disqus_observer.observe(document.getElementById('disqus_thread'));
} else {
t();
}
}, 1);
},!0
);
</script>
<% } %>
|
如果经过上面的优化,你还对博客的加载速度不满意,那一定是 github pages 服务器在美国的原因,200+ms 的延迟导致首字节返回时间不短
其实支持通过 GitHub 仓库代码进行构建,部署为静态网站的平台不值 github pages 一家,我使用过的比较好的是 zeit.co
, 国内访问走的是台湾的 gcp 节点,延迟低速度快,推荐
具体使用方法非常简单,自行摸索吧
更新: 刚知道,如果更新太快的话,zeit 会暂停构建部署的
You are pushing commits at a very fast pace (across the whole organization).
Due to that, we cannot deploy the commit e80751b.
You can try again later or upgrade your plan.
使用谷歌提供的 Pagespeed Insights 工具分析网页加载并根据建议进行优化