这篇记录了一次对博客的"大扫除":从 hexo 突然跑不起来开始,一路排查环境、备份源码、修站点配置、整理全部笔记、更换 Markdown 渲染器、重做全站样式,最后补齐框架上缺的功能。每个问题都写了现象 → 原因 → 解决办法,最后一节是还没处理的问题和打算怎么做。

博客环境:Hexo 7.3 + Butterfly 4.13,部署在 GitHub Pages。

一、环境故障

1. hexo 命令全部报错

现象:

1
2
3
E:\Blog>hexo s
ERROR Cannot find module 'hexo' from 'E:\Blog'
ERROR Local hexo loading failed in E:\Blog

原因:node_modules 被"掏空"了——740 个文件夹只剩 22 个文件,node_modules/hexo 里只有空的 bin/ 和 dist/,连 package.json 都没有。文件夹的修改时间晚于最后一次成功生成的时间,应该是某次中断的 npm 操作、清理软件或同步盘把文件删了。

1
2
3
# 判断 node_modules 是否被掏空
find node_modules -type f | wc -l
node -e "require.resolve('hexo')"

解决:package.json 和 package-lock.json 完好,按锁文件重装:

1
2
npm ci          # 删掉 node_modules,严格按 package-lock.json 重装,版本和原来一致
hexo clean && hexo g

2. 重装后头像、背景图、网站图标都没了

原因:自定义图片当初被放进了 node_modules/hexo-theme-butterfly/source/img/。主题是 npm 装的,node_modules 一重装就被还原成官方默认文件。

解决:从上次部署留下的 .deploy_git/img/ 找回原图,放到博客根目录的 source/img/。Hexo 会把 source/ 下的文件原样复制到站点根目录,配置里的 /img/xxx.jpg 不用改。

原则:永远不要改 node_modules 里的东西。 自定义图片放 source/img/,自定义样式和脚本放 source/css/、source/js/,再用 _config.butterfly.yml 的 inject 引入。

3. 源码只有本地一份

GitHub 上的 xxx.github.io 仓库存的只是 hexo d 生成的网页,Markdown 原稿、图片、配置都只在本地。

解决:新建一个私有仓库 blog-source 专门存源码(不要放进公开的 github.io 仓库)。Hexo 自带的 .gitignore 已经排除了 node_modules/、public/、.deploy*/、db.json。

1
2
3
4
5
6
7
8
9
git init -b main
git add .
git commit -m "博客源码首次备份"
git remote add origin https://github.com/<用户名>/blog-source.git
git push -u origin main

# 换电脑恢复
git clone https://github.com/<用户名>/blog-source.git Blog
cd Blog && npm ci && hexo s

GitHub 仓库页面可能提示 “Your main branch isn’t protected”。分支保护在免费账号的私有仓库上用不了,单人备份仓库也不需要,点 Dismiss 即可。

二、站点配置

都在根目录 _config.yml:

问题 原来 改成 影响
站点地址 http://example.com https://<用户名>.github.io 文章底部"本文链接"、分享链接都靠它
时区 "" Asia/Shanghai 留空时换机器可能出现日期差 8 小时
副标题/描述/关键词 空 填上 description 会写进页面的 meta,影响搜索引擎展示

依赖清理:

1
2
npm uninstall hexo-theme-landscape   # hexo init 自带的默认主题,用 Butterfly 后没用了
npm update hexo-asset-img # 小版本升级

hexo 7→8、Butterfly 4→5 是大版本升级,配置项变化大,暂时不动。

三、文章整理

4. 分类与标签

问题:所有文章都没有 categories,只有 Study / Algorithm / Web 这几个很粗的标签,而且划分不一致;有一篇写成了 tag:(少个 s,Hexo 不认,等于没标签);还留着 Hexo 默认的 hello-world.md。

方案:分类按技术领域,“面经”"八股"这类性质用标签表达。

分类 内容
前端开发 HTML+CSS、JS、Vue、若依
AI与深度学习 机器学习、PyTorch、Transformer、多模态、大模型微调、Agent 面经
推荐系统 推荐系统笔记与八股、FTRL、天池代码解读、搜广推面经
算法刷题 hot100、ACM 输入
工具与环境 Git、Missing Semester、Hexo

标签 = 内容性质(学习笔记 / 面经 / 八股 / 项目实战)+ 具体技术(PyTorch、Transformer、Vue……)。

permalink 用了 :title,把文章挪进子文件夹会让 :title 带上路径、文章链接改变,所以分类只改 front-matter,不移动文件。

5. 内容细节

  • 错别字:XBoost → XGBoost,演讲过程 → 演进过程
  • 8 篇笔记正文开头又写了一遍 # 标题,和文章标题重复,删掉
  • 17 个代码块没写语言(没有高亮),补上 python / bash / json / text
  • JS 笔记(4200 行)拆成 4 篇、HTML+CSS 笔记(1900 行)拆成 2 篇:
    • 第一篇沿用原文件名,原链接不失效
    • 图片跟着内容移到各自的资源文件夹
    • 每篇开头加系列导航(用 Hexo 的 post_link 标签互相链接)

小坑:hexo-asset-img 给每张图生成随机类名,偶尔以 www 开头时会被 Hexo 的 img 标签误判为网址,导致那张图显示不出来。重新 hexo g 一次就好。

四、更换 Markdown 渲染器

6. 公式显示错乱

现象:部分公式里的下标乱掉,变成斜体。

原因:原来的渲染器 hexo-renderer-kramed 早已停止维护,而且不认识公式:它先把公式里的两个 _ 当成斜体标记,等浏览器端 MathJax 再来渲染时公式已经坏了。

解决:换成 markdown-it,并在生成时直接把公式渲染成 SVG:

1
2
npm uninstall hexo-renderer-kramed
npm install hexo-renderer-markdown-it markdown-it-mathjax3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# _config.yml
markdown:
preset: 'default'
render:
html: true
breaks: true # 和原来 kramed 的 breaks: true 一致
linkify: true
typographer: true # 弯引号
quotes: '“”‘’'
disable_rules:
- replacements # 关掉 (r)→®、(c)→© 这类自动替换
plugins:
- markdown-it-mathjax3
anchors:
level: 1 # 一级标题也生成锚点,目录才能跳转

同时在 _config.butterfly.yml 里关掉浏览器端的 mathjax.enable,避免重复处理。

7. 换渲染器后冒出来的问题

问题 原因 解决
加粗紧挨中文标点时不生效,显示成 ** CommonMark 规范对中日韩标点的判定有缺陷 装 markdown-it-cjk-friendly;它是 ES 模块,不能直接写进 plugins,改用 scripts/markdown-it-cjk.js 通过渲染器的过滤器注册
侧边目录里显示出一大段 CSS mathjax3 在每个公式外面内联约 3KB 的样式,标题里有公式时被目录抓走 scripts/mathjax-style.js 在渲染后去掉内联样式,样式统一放到 source/css/mathjax.css 加载一次
(r) 变成 ® typographer 的替换规则 disable_rules: replacements

8. 标准 Markdown 比 Typora 严格

Typora 能容忍、但标准 Markdown 不认的写法,换渲染器后要改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- 公式定界符里不要有空格 -->
错:$ \sum g_s $ 对:$\sum g_s$

<!-- 行内公式用单个 $,$$ 要单独成行 -->
错:就得到了 $$\sum g_s$$
对:就得到了 $\sum g_s$

<!-- 用 & 对齐的多行公式要包在 aligned 里 -->
$$
\begin{aligned}
a &= b + c \\
&= d
\end{aligned}
$$

<!-- 标题 # 后面要有空格 -->
错:##操作元素属性 对:## 操作元素属性

<!-- 加粗的 ** 里侧不要有空格 -->
错:**解决: ** 对:**解决:**

<!-- 列表项不要空着,内容写在同一行 -->

改完后线上看到的公式还是坏的?那是线上还没部署,或者看的是换渲染器之前启动的 hexo s。重启服务器 / 部署后 Ctrl+F5 强制刷新。

五、样式

所有样式都在 source/css/custom.css,通过 _config.butterfly.yml 引入,不改主题文件:

1
2
3
4
5
6
inject:
head:
- <link rel="stylesheet" href="/css/mathjax.css">
- <link rel="stylesheet" href="/css/custom.css">
bottom:
- <script src="/js/code-tools.js"></script>

9. 全站:参考 Apple 官网的设计语言

  • 颜色:浅灰背景 + 白色卡片,近黑文字,蓝色强调;所有颜色定义成 CSS 变量,深色模式另配一套
  • 卡片大圆角、柔和阴影、悬停微微上浮;按钮和标签胶囊形;导航栏滚动后毛玻璃
  • 正文标题靠字号、字重、留白区分层级;加粗用淡蓝"荧光笔"高亮;嵌套列表加缩进和细线
  • 引用块、表格、图片圆角化;无封面的"相关推荐/上下篇"改成浅灰卡片
  • 直接覆盖 Butterfly 自带的变量(如 --card-bg、--font-color)最省事;深色模式要用 :root[data-theme="dark"] 才能压过主题自己的定义

10. 代码块

问题 1:工具栏的复制、折叠图标显示成问号。
原因是我给 figure.highlight *(代码块里所有元素)设了等宽字体,把图标字体也覆盖了。改成只作用于 pre, code, .line。

问题 2:想要深色 Mac 窗口风格。

  • highlight_theme: mac:深色背景 + 红黄绿三个圆点
  • 工具栏右侧改成 [语言] [复制] [全屏] 小按钮,窄屏只显示图标
  • 主题没有全屏功能,用 source/js/code-tools.js 加了一个,Esc 退出
  • 行号用 CSS 隐藏,而不是在配置里关掉——因为主题的复制功能依赖行号的表格结构

小坑:主题复制成功后,会把"复制成功"写进工具栏最后一个元素的前一个元素。全屏按钮如果直接追加在末尾,提示就会写进复制按钮里并把它隐藏。所以全屏按钮要插在复制提示前面,显示顺序交给 CSS 的 order。

六、框架功能

11. 分类页、标签页 404,导航栏是空的

现象:/categories/、/tags/ 打不开;顶部导航只有站名。

原因:这两个页面需要手动创建;menu 配置全被注释掉了。而且菜单为空时,Butterfly 的 JS 每次加载页面都会报错(找不到侧栏菜单元素),后面的部分初始化代码也就没执行。

解决:

1
2
3
4
5
6
7
8
9
10
11
<!-- source/categories/index.md -->
---
title: 分类
type: "categories"
---

<!-- source/tags/index.md -->
---
title: 标签
type: "tags"
---
1
2
3
4
5
6
# _config.butterfly.yml
menu:
首页: / || fas fa-home
归档: /archives/ || fas fa-archive
分类: /categories/ || fas fa-folder-open
标签: /tags/ || fas fa-tags

12. 没有站内搜索

1
npm install hexo-generator-searchdb
1
2
3
4
5
6
7
8
9
10
# _config.yml
search:
path: search.json
field: post
content: true
format: striptags # 只保留文字,公式的 SVG 不进索引

# _config.butterfly.yml
local_search:
enable: true

索引约 470KB,只在点开搜索时才下载,不影响平时打开页面的速度。

13. 其他

  • 页脚 since: 2020 → 2024(第一篇笔记是 2024 年的)
  • 「hexo常见问题」里讲旧公式方案的一节标注为已过时

七、还没处理的问题

问题 打算怎么做
图片多的笔记加载慢(推荐系统学习笔记 115 张、12MB) 开启 Butterfly 的 lazyload,图片滚动到附近才加载
侧栏公告还是默认的 “This is my Blog” 写一段博客简介 + 使用提示
首页摘要直接截正文开头,很乱 每篇 front-matter 加一句 description,index_post_content.method 改成 2
没有"关于"页面 新建 source/about/index.md,菜单加"关于"
JS 笔记缺 3 张演示 gif 装饰性的删掉;演示效果的用 ScreenToGif 自己录一段
部分笔记有只写了标题的空章节 之后补内容
约 13 张没被引用的图片、4 个空资源文件夹 之后清理
各篇笔记标题层级不统一(有的用 # 分章节) 之后统一从 ## 开始

八、当前的文件结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
E:\Blog
├── _config.yml # 站点配置:url、渲染器、搜索
├── _config.butterfly.yml # 主题配置:菜单、代码块、inject
├── scripts/ # Hexo 启动时自动加载
│ ├── markdown-it-cjk.js # 加粗紧挨中文标点
│ └── mathjax-style.js # 去掉公式的内联样式
└── source/
├── _posts/ # 笔记 + 同名图片文件夹
├── categories/index.md # 分类页
├── tags/index.md # 标签页
├── css/
│ ├── custom.css # 全站样式
│ └── mathjax.css # 公式样式
├── js/code-tools.js # 代码块全屏
└── img/ # 头像、背景等自定义图片

九、常用命令

1
2
3
4
5
6
7
8
9
hexo clean     # 清缓存和 public(不是 hexo clear)
hexo g # 生成
hexo s # 本地预览 http://localhost:4000(不是 hexo see)
hexo d # 部署到 GitHub Pages
hexo new 标题 # 新建文章

# 改了 _config*.yml 或 scripts/ 之后,要重启 hexo s 才生效
# 改了源码记得备份
git add . && git commit -m "说明" && git push