出于完美主义心理,我总在努力优化我博客的浏览体验,不断加入个性化的内容。但是,在网站内容愈发丰富的同时,我发现一个问题:访问速度不稳定,特别是晚上八九点钟和早上六点半。半个月前,在早上六点半使用多节点测速工具测速时,会发现有大片的浅绿色和不少红色的小闪电。这是不应该,也是不允许的。

于是我就试着加速优化我的博客。经过一段时间的摸索,我成功优化提速。现在访问速度还可以接受:

PixPin_2025-05-16_21-45-06

于是就有了这篇文章。我将会谈谈方案和踩过的坑。

1
2
3
NPM version: 11.3.0
Hexo version: 7.3.0
theme: butterfly v5.2.2

不同的版本之间操作可能略有差异。请仔细甄别。

CDN 优化

大概在去年十二月起,至今年二月,我一直在使用 unpkg.com 的免费 cdn。期间试图优化,但是由于没看懂配置文件给出的注释,我自己多次尝试发现自定义 cdn 效果不理想,不敢操作。

直到我偶然间发现了 [BlogRoot]\themes\butterfly\scripts\events\cdn.js 这个文件,这个状况才得以解决。其中有一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
const cdnSource = {
local:
cond === "internal"
? `${cdnjs_file + verType}`
: `/pluginsSrc/${name}/${file + verType}`,
jsdelivr: `https://cdn.jsdelivr.net/npm/${name}${verType}/${min_file}`,
unpkg: `https://unpkg.com/${name}${verType}/${file}`,
cdnjs: `https://cdnjs.cloudflare.com/ajax/libs/${cdnjs_name}/${version}/${min_cdnjs_file}`,
custom: (CDN.custom_format || "").replace(
/\$\{(.+?)\}/g,
(match, $1) => value[$1]
),
};

所以,我大胆地将大部分 CDN 换成了字节跳动饿了么的;还有没被同步的,我就用了 zstatic

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
74
# CDN Settings
# Don't modify the following settings unless you know how they work
CDN:
# The CDN provider for internal and third-party scripts
# Options for both: local/jsdelivr/unpkg/cdnjs/custom
# Note: Dev version can only use 'local' for internal scripts
# Note: When setting third-party scripts to 'local', you need to install hexo-butterfly-extjs
internal_provider: local
third_party_provider: custom

# Add version number to url, true or false
version: true

# Custom format
# For example: https://cdn.staticfile.org/${cdnjs_name}/${version}/${min_cdnjs_file}
custom_format: https://npm.elemecdn.com/${name}@${version}/${file}

option:
# abcjs_basic_js:
# activate_power_mode:
# algolia_js:
# algolia_search:
aplayer_css: https://npm.elemecdn.com/aplayer@1.10.1/dist/APlayer.min.css
aplayer_js: https://npm.elemecdn.com/aplayer@1.10.1/dist/APlayer.min.js
# artalk_css:
# artalk_js:
# blueimp_md5:
# busuanzi:
# canvas_fluttering_ribbon:
# canvas_nest:
# canvas_ribbon:
# chartjs:
# click_heart:
# clickShowText:
# disqusjs:
# disqusjs_css:
# docsearch_css:
# docsearch_js:
egjs_infinitegrid: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/egjs-infinitegrid/4.2.0-beta.6/infinitegrid.min.js
fancybox_css: https://lf6-unpkg.zstaticcdn.com/@fancyapps/ui@5.0.36/dist/fancybox/fancybox.css
fancybox: https://lf6-unpkg.zstaticcdn.com/@fancyapps/ui@5.0.36/dist/fancybox/fancybox.umd.js
# fireworks:
fontawesome: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/font-awesome/6.0.0/css/all.min.css
# gitalk:
# gitalk_css:
# giscus:
# instantpage:
# instantsearch:
katex: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/KaTeX/0.10.0/katex.min.css
# katex_copytex:
lazyload: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/vanilla-lazyload/17.3.1/lazyload.iife.min.js
# local_search:
# main:
# main_css:
# mathjax:
# medium_zoom:
# mermaid:
# meting_js:
pangu: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/pangu/4.0.7/pangu.min.js
prismjs_js: https://cdn1.tianli0.top/npm/prismjs@1.1.0/prism.js
prismjs_lineNumber_js: https://cdn1.tianli0.top/npm/prismjs/plugins/line-numbers/prism-line-numbers.min.js
prismjs_autoloader: https://cdn1.tianli0.top/npm/prismjs/plugins/autoloader/prism-autoloader.min.js
pjax: https://lib.baomitu.com/pjax/0.2.8/pjax.min.js
sharejs: https://lib.baomitu.com/social-share.js/1.0.16/js/social-share.min.js
sharejs_css: https://lib.baomitu.com/social-share.js/1.0.16/css/share.min.css
snackbar: https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-M/node-snackbar/0.1.16/snackbar.min.js
snackbar_css: https://lf3-cdn-tos.bytecdntp.com/cdn/expire-1-M/node-snackbar/0.1.16/snackbar.min.css
# translate:
# twikoo:
typed: https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/typed.js/2.0.12/typed.min.js
# utils:
# valine:
waline_css: https://lf6-unpkg.zstaticcdn.com/@waline/client@3.5.6/dist/waline.css
waline_js: https://lf6-unpkg.zstaticcdn.com/@waline/client@3.5.6/dist/waline.js

可惜的是,我至今仍然不知道为什么 npmmirror 提供的 cdn 链接无法用于我的网站。这会被 CORS 拦截掉,导致 403。如果我有更好的方案,我将会在这里继续更新。

DNS 解析优化

网站速度慢的另一个原因是DNS 解析慢。我原来使用的是 Netlify DNS,因为网站最初是在 netlify 上部署的。后来又喜欢上了 vercel,就在 vercel 部署;把域名放到国内的 DNSPOD 上,把解析记录一条条地填进去。

这个没什么好说的,我现在使用了 vercel 优选 IP。就是将 CNAME 解析记录的值全部由 cname-china.vercel-dns.com 换为 vercel-cname.xingpingcn.top.

开启 Vercel 缓存

这个要感谢 deepseek,它告诉我:开启 vercel 的缓存会对速度提升有奇效。

具体的操作方式,就是创建 [BlogRoot]\themes\butterfly\source\vercel.json,放入以下配置:

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
{
"headers": [
{
"source": "/sw.js",
"headers": [
{
"key": "Cache-Control",
"value": "no-cache, no-store, must-revalidate"
}
]
},
{
"source": "**/*.(js|css|png|jpg|svg|webp|woff2)",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "**",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=60, s-maxage=600"
}
]
}
]
}

尽管它的功效我不非常明确,但是我把它放到博客里,就当图个心理安慰吧。

图片

图片压缩

我推荐 在线免费图像转换器 | 本地运行 这个工具,效果还是不错的。

懒加载

我所使用的 butterfly 主题的 5.2.2 版本中,对于图片懒加载的配置好像有点问题。当我进行如下配置时,主页面上的图片有懒加载效果,但是在文章的页面中,所有图片就无法正常加载。

1
2
3
4
5
6
7
8
# Lazyload
# https://github.com/verlok/vanilla-lazyload
lazyload:
enable: true
# Specify the field to use lazyload (site or post)
field: site
placeholder:
blur: true

我直接找到了负责懒加载的 JS 文件——[BlogRoot]\themes\butterfly\scripts\filters\post_lazyload.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
/**
* Butterfly
* lazyload
* replace src to data-lazy-src
*/

"use strict";

const urlFor = require("hexo-util").url_for.bind(hexo);

const lazyload = (htmlContent) => {
const bg = hexo.theme.config.lazyload.placeholder
? urlFor(hexo.theme.config.lazyload.placeholder)
: "data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7";
return htmlContent.replace(/(<img.*? src=)/gi, `$1 "${bg}" data-lazy-src=`);
};

hexo.extend.filter.register("after_render:html", (data) => {
const { enable, field } = hexo.theme.config.lazyload;
if (!enable) return;
return lazyload(data);
});

// hexo.extend.filter.register('after_render:html', data => {
// const { enable, field } = hexo.theme.config.lazyload
// if (!enable || field !== 'site') return
// return lazyload(data)
// })

// hexo.extend.filter.register('after_post_render', data => {
// const { enable, field } = hexo.theme.config.lazyload
// if (!enable || field !== 'post') return
// data.content = lazyload(data.content)
// return data
// })

这样就忽略了 field 开关,不管是哪里的图片,都是懒加载。

Pjax

犹记得,我在 2 月 21 日发了一条动态:

我愿称你 pjax 为 bug 巨头!

pjax 的原理是页面跳转时只加载不同的内容。其配置项如下:

1
2
3
4
5
6
7
# https://github.com/MoOx/pjax
pjax:
enable: true
# Exclude the specified pages from pjax, such as '/music/'
exclude:
# - /xxxxxx/
- /moments/

我选择避开 moments动态页面。如果不避开,整个 artitalk 都不会正常加载。

对,pjax 就可能出这种玄学错误,甚至是幽灵错误,而且我不会改。

谨慎使用。

Instant Page

1
2
3
# Instant.page
# https://instant.page/
instantpage: true

就是它。打开这个功能后,它将会依据你的鼠标在链接上停留的时长,预估你是否会访问链接。这是有效的。

压缩 HTML

我选择的插件是 hexo-neat。使用 cnpm in hexo-neat 安装后,我在 [BlogRoot]\_config.yml 添加了如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
neat_enable: true
neat_html:
enable: true
minifyJS: true
minifyCSS: true
exclude:
neat_css:
enable: true
exclude:
- "*.min.css"
- "**/*.min.css"
- "**/custom.css"
neat_js:
enable: true
mangle: true
output:
compress:
exclude:
- "*.min.js"
- "**/*.min.js"

当你 hexo g 时,你就能发现:

PixPin_2025-05-16_22-27-49

这也是有效的。

但是,这可能会延长你部署的时长。


不断更新……