问题描述

使用Hexo博客部署到GitHub Pages后,经常遇到一个困扰的问题:每次hexo deploy部署后,博客的新内容在浏览器中不会立即显示,必须手动清理浏览器缓存(Ctrl+Shift+R)才能看到更新。

问题本质:浏览器会缓存CSS、JS等静态资源来优化性能,但当这些资源更新时,由于URL相同,浏览器继续使用旧的缓存内容。

1
2
3
<!-- 每次生成的HTML都是相同的URL -->
<link rel="stylesheet" href="/css/index.css" />
<script src="/js/main.js"></script>

解决方案

核心思路:为静态资源添加版本号,强制浏览器重新下载更新的文件。

方案设计

采用三层缓存控制机制:

  1. HTML页面缓存控制:通过Meta标签禁止缓存HTML
  2. 静态资源版本控制:为本地CSS/JS添加时间戳版本号
  3. CDN资源保护:保持第三方CDN资源不变

技术实现

创建scripts/cache-buster.js文件,利用Hexo的after_render:html钩子自动处理:

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
// scripts/cache-buster.js
hexo.extend.filter.register("after_render:html", function (str, data) {
if (!str) return str;

const timestamp = Date.now();

// 处理CSS资源
str = str.replace(
/(<link[^>]*href=["']?)([^"'?]+\.css)(\?[^"']*)?["']/g,
(match, prefix, url, query) => {
// 跳过CDN和外部资源
if (
url.includes("cdn.") ||
url.includes("://") ||
url.startsWith("http")
) {
return match;
}
// 避免重复添加版本号
if (query && query.includes("v=")) {
return match;
}
return `${prefix}${url}?v=${timestamp}"`;
}
);

// 处理JS资源
str = str.replace(
/(<script[^>]*src=["']?)([^"'?]+\.js)(\?[^"']*)?["']/g,
(match, prefix, url, query) => {
if (
url.includes("cdn.") ||
url.includes("://") ||
url.startsWith("http")
) {
return match;
}
if (query && query.includes("v=")) {
return match;
}
return `${prefix}${url}?v=${timestamp}"`;
}
);

return str;
});

配置步骤

1. 添加HTML缓存控制

编辑主题模板文件themes/butterfly/layout/includes/head.pug,添加:

1
2
3
meta(http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate")
meta(http-equiv="Pragma" content="no-cache")
meta(http-equiv="Expires" content="0")

2. 启用CDN版本控制

编辑themes/butterfly/_config.yml

1
2
CDN:
version: true # 启用CDN资源版本控制

验证效果

命令行验证

1
2
3
4
5
6
7
8
# 生成并检查
hexo clean && hexo generate

# 检查CSS资源版本化
grep -n "\.css?v=" public/index.html

# 检查JS资源版本化
grep -n "\.js?v=" public/index.html

预期输出

1
2
15:<link rel="stylesheet" href="/css/index.css?v=1690123456789" />
28:<script src="/js/main.js?v=1690123456789"></script>

浏览器验证

  1. 部署博客后,打开开发者工具的Network面板
  2. 刷新页面,检查静态资源的URL是否包含版本号
  3. 再次部署,确认版本号已更新

使用说明

配置完成后,继续使用原有的Hexo工作流程即可:

1
2
3
4
5
# 标准流程
hexo clean && hexo generate && hexo deploy

# 或简写
hexo cl && hexo g && hexo d

每次执行hexo generate时,系统会自动:

  • 为所有本地CSS/JS文件添加当前时间戳
  • 保持CDN资源链接不变
  • 确保HTML页面不被缓存

扩展功能

支持更多资源类型

如需支持图片资源版本控制,可在脚本中添加:

1
2
3
4
5
6
7
8
9
10
11
12
13
// 支持图片资源版本控制
str = str.replace(
/(<img[^>]*src=["']?)([^"'?]+\.(png|jpg|jpeg|gif|webp))(\?[^"']*)?["']/g,
(match, prefix, url, ext, query) => {
if (url.includes("cdn.") || url.includes("://") || url.startsWith("http")) {
return match;
}
if (query && query.includes("v=")) {
return match;
}
return `${prefix}${url}?v=${timestamp}"`;
}
);

环境区分

只在生产环境启用缓存清理:

1
2
3
4
// 只在生产环境启用
if (hexo.env.cmd === "generate" && process.env.NODE_ENV === "production") {
// 添加版本号逻辑
}

总结

这个解决方案具有以下优点:

  • 自动化:集成到Hexo生成流程,无需额外操作
  • 智能化:区分本地资源和CDN资源,精确控制
  • 兼容性:保持原有工作流程不变
  • 高效性:最小化性能影响

配置完成后,每次部署博客内容都能立即更新,彻底解决缓存问题。