建站一周年:从 NotionNext 迁移到 Hexo 安知鱼

建站一周年:从 NotionNext 迁移到 Hexo 安知鱼
青萍叙事时间过得很快,从去年四月建站到现在,整整一年了。
这一年来,网站经历了从零搭建、持续日更、产品化探索等多个阶段。
但在一周年之际,我做了一个重要决定:从 NotionNext 迁移到 Hexo 安知鱼主题。
这篇文章,就是这次迁移的完整记录。
🧭 背景:为什么要迁移?
NotionNext 之痛
我最初选择 NotionNext 作为博客框架,核心原因是内容管理使用 Notion,写作体验非常好。
但使用一年下来,最大的痛点也逐渐暴露:
Notion 上游 API 频繁变更,导致经常无法构建发布。
对于一个博客来说,稳定是第一位的。
你无法接受写了一篇文章,发布时发现构建失败了,而且你无法控制什么时候能修复——因为这取决于 Notion 的 API 变更和 NotionNext 项目的适配速度。
这种不确定性对于一个需要持续输出的博客来说是致命的。
为什么是 Hexo 安知鱼?
选定 Hexo + 安知鱼主题,主要有两个原因:
Hexo 是老朋友。我很早以前就使用过 Hexo,对其工作机制非常熟悉,静态站点生成器的稳定性和可控性是动态依赖 Notion API 的方案无法比拟的。
安知鱼与 Heo 主题几乎一模一样。之前 NotionNext 使用的是 Heo 主题风格,安知鱼主题的设计风格与 Heo 几乎一致,这意味着我只需要少量的定制改造就能还原之前的视觉效果,迁移成本极低。
📦 从 Notion 迁移数据
迁移的第一步,是把 Notion 中的所有文章数据导出来。
1. 导出 Markdown
Notion 支持将页面导出为 Markdown 格式。但直接导出有几个问题:
- 只导出了 Markdown,缺少封面图
- 缺少 Hexo 需要的 front-matter 元数据
- AI 摘要信息丢失,需从之前的缓存中读取
2. API 获取封面链接
Notion 导出的 Markdown 不包含封面图信息,需要通过 Notion API 补全:
1 | import requests |
通过 API 遍历数据库中所有文章,提取封面链接并下载到自己的 青萍 AI 图床。
3. front-matter 格式转换
NotionNext 的 front-matter 格式与 Hexo 不同,需要转换。核心字段映射如下:
| NotionNext | Hexo | 说明 |
|---|---|---|
| title | title | 文章标题 |
| date | date | 发布日期 |
| summary | description | 文章摘要 |
| category | categories | 分类(Hexo 支持层级) |
| tags | tags | 标签 |
| slug | permalink | URL 别名 |
| cover | cover | 封面图 |
转换脚本会将每篇文章的 front-matter 从 NotionNext 格式转为 Hexo 格式,同时处理分类和标签的映射关系。
经过以上三个步骤,二百多篇文章就从 Notion 成功迁移到了 Hexo 的 source/_posts/ 目录。
🔧 Hexo 搭建与配置
数据准备好后,就是搭建 Hexo 站点和配置安知鱼主题。
1. 主题下载
1 | # 初始化 Hexo 站点 |
在 _config.yml 中启用主题:
1 | theme: anzhiyu |
2. 基础配置修改
安知鱼主题的配置项非常多,主要集中在 _config.anzhiyu.yml 中。
导航菜单
1 | menu: |
分页配置
1 | index_generator: |
页脚、站长信息
配置页脚的社交链接、版权信息、建站时间等,确保与旧站一致。
封面和字体
将全站字体和封面图替换为自己的 CDN 资源,提升加载速度。
3. 扩展页面
安知鱼主题支持多种扩展页面,我逐一搭建了以下页面:
- links:友情链接页面,展示友链卡片
- about:关于页面,包含个人信息、技能点、联系方式
- moments:日常瞬间页面,类似朋友圈的短内容
- friends:朋友圈页面,聚合友站最新动态
- comments:留言板页面,接入 Twikoo 评论系统
- music:音乐馆页面
- categories:分类总览页面
每个页面都是独立的 Markdown 文件,放在 source/ 对应目录下。
4. 主题定制
安知鱼主题虽然开箱即用很棒,但要完美还原之前的 Heo 风格,还需要一些定制改造。
导航菜单改为垂直
安知鱼默认的导航菜单是水平排列的,让子菜单更多时比较难看,并且之前的 Heo 风格是垂直分组展示。
修改了 nav.pug 模板和 nav.styl 样式,将菜单改为垂直分组展示,每个一级菜单作为一个分组,二级菜单垂直排列。
右侧面板添加板块
在文章详情页的右侧面板中,增加了以下信息卡片:
- 最新瞬间:展示最近的日常瞬间动态
- 最近查看:展示最近更新的文章
- 最新评论:接入 Twikoo 展示最新评论
- 标签:展示标签云,方便快速导航
这些卡片通过修改 Pug 模板和 Stylus 样式实现,部分通过自定义 widget 组件完成。
站点统计添加 vercount
之前在 NotionNext 中就使用了自己部署的 vercount,迁移到 Hexo 后继续使用:
1 | vercount: |
vercount 与不蒜子相比,数据更稳定,加载更快,而且支持自托管。
友链卡片定制
安知鱼默认的友链卡片样式比较简单。为了更好地展示友链信息,我新增了 flexcard-large 样式:
- 更大的头像尺寸
- 更清晰的信息层级
- 更好的视觉效果
添加 RSS 集成
RSS 订阅是博客的基础功能,通过 hexo-generator-feed 插件实现:
1 | feed: |
为保持兼容,修改 path。
Algolia 搜索添加 slug 支持兼容
之前 NotionNext 使用 Algolia 搜索,文章 URL 格式为 /article/slug。迁移到 Hexo 后,需要确保搜索结果中的链接格式一致。
修改了搜索索引的生成逻辑,确保 slug 字段正确映射到 permalink,保持搜索结果的 URL 兼容性。
首页文章卡片添加简短摘要信息显示
安知鱼主题默认的首页文章卡片只显示标题、分类、标签和发布日期,缺少文章的摘要预览。
为了提升首页的信息密度,让访客快速了解每篇文章的内容,我对卡片布局进行了调整:
- 将文章描述(description)内容显示在标题和标签之间。
- 配置
index_post_content.method: 2,优先使用 front-matter 中的description字段,没有则自动截取正文 - 标签和发布日期下移至卡片底部,与描述内容形成清晰的信息层级
文章详情页面左侧添加文章目录
安知鱼主题默认将文章目录(TOC)放在右侧面板中,但右侧面板已经包含了最新瞬间、最近查看、最新评论、标签云等多个信息卡片,信息密度非常高。
而且默认的 TOC 在滚动时会隐藏,实用性大打折扣,尤其是对于长篇技术文章。
为了提升阅读体验,我在文章详情页左侧新增了独立的 sticky 定位目录组件。
这样右侧面板专注于站点信息展示,左侧目录专注于文章导航,互不干扰。
5. URL 路径兼容
这是一个容易被忽视但非常重要的细节。
之前 NotionNext 的文章 URL 格式是 /article/slug,没有 .html 后缀也没有尾部斜杠。而 Hexo 默认生成的路径会在后面自动带上 .html 或 /,比如 /article/slug.html 或 /article/slug/。
网站已经运营了一年,搜索引擎已经积累了大量的索引,如果 URL 格式变化会导致:
- 搜索引擎收录的旧链接全部 404
- 外部引用和友链失效
- SEO 权重归零
解决方案分三步:
第一步,Hexo permalink 配置
在 _config.yml 中手动设置 permalink 格式,让生成的文件路径包含 .html:
1 | permalink: article/:slug.html |
但 Hexo 默认的 :slug 是基于目录名 + 文章标题生成的,与我之前的 slug 格式不一致。
因此通过 Hexo 的 post_permalink 过滤器,从每篇文章的 front-matter 中读取自定义的 slug 字段来生成 permalink:
1 | hexo.extend.filter.register("post_permalink", function (data) { |
这样 Hexo 生成的静态文件就会使用文章 front-matter 中指定的 slug,与旧站的 URL 路径完全一致。
第二步,Nginx try_files 配置
但还有一个问题:旧站的 URL 是 /article/slug(无 .html),而实际文件是 /article/slug.html。需要在 Nginx 层面做兼容,让无后缀的请求也能正确访问:
1 | location / { |
关键在于 try_files 指令的 $uri.html——当请求 /article/slug 时,Nginx 会依次尝试:
/article/slug(原路径,不存在)/article/slug.html(拼接 .html,命中!)/article/slug/index.html(目录下的 index)- 返回 404
这样无论访问 /article/slug 还是 /article/slug.html 都能正常访问,完美保持了与旧站的 URL 兼容性。
6. 静态资源,全站 CDN 切换
最后一步是将所有静态资源切换到自己的 CDN,涵盖 CSS/JS 资源、字体文件、图片资源(favicon、logo 等)以及第三方库(Twikoo、vercount 等前端脚本)。
我编写了一个脚本,自动扫描主题配置中引用的所有远程 CDN 资源并批量下载到自己的 青萍 AI 图床,然后将主题配置中的 CDN 地址统一替换为 cdn.lusyoe.com。
整个过程一键完成,无需手动逐个替换,大幅提升了资源加载速度。
🚀 部署
部署方案沿用了之前的 Docker + Nginx 方式:
1 | FROM nginx:alpine |
📊 迁移对比
| 对比项 | NotionNext | Hexo 安知鱼 |
|---|---|---|
| 内容管理 | Notion | Markdown 文件 |
| 构建稳定性 | 依赖 Notion API | 本地构建,完全可控 |
| 主题风格 | Heo | 安知鱼(几乎一致) |
| 部署方式 | Docker + Nginx | Docker + Nginx |
| 搜索 | Algolia | Algolia(兼容) |
| 评论 | Twikoo | Twikoo |
| 计数 | vercount | vercount |
| CDN | 阿里云 ESA | 阿里云 ESA |
| 写作体验 | Notion 编辑器 | Markdown 编辑器 |
| 构建速度 | 较慢(依赖 API) | 秒级 |
💭 写在最后
建站一周年,从 NotionNext 迁移到 Hexo,这次迁移总共只花了 2天 时间,表面上看是技术栈的变更,但本质上是对稳定性的追求。
NotionNext 是一个非常优秀的项目,它让我快速搭建了博客,也让我体验到了 Notion 写作的便利。
但当博客发展到一定阶段,稳定可控比方便快捷更重要。
迁移过程虽然有些繁琐,但结果令人满意。Hexo 的静态生成完全可控,不再受上游 API 变更的影响。
安知鱼主题的视觉效果与之前的 Heo 风格几乎一致,甚至略超一筹,迁移成本远低于预期。
如果你也在使用 NotionNext 并且遇到了类似的稳定性问题,或者正在考虑搭建博客,希望这篇文章能给你一些参考。














