博客架构演进史:从 Hexo 到 Astro 的「无缝」肉身替换实录
本文记录了我将个人博客从传统的 Hexo 框架彻底迁移至现代 Astro 框架的全过程。这不仅是一次技术的迭代,更是为了追求极致的开发体验与近乎完美的站点性能。
1. 迁移背景:
旧博客基于 Hexo (Butterfly 主题),采用 npm 安装模式。现在尝试无缝切去 Astro 继续折腾。
2. 核心迁移策略:原地替换,内容至上
最稳妥的迁移方法是 「原地替换」 ,即在原有的 Git 目录下,清理 Hexo 引擎,注入 Astro 引擎,但必须 确保文章源码(Markdown)绝对安全 。
迁移前的目录结构 (Hexo npm 模式)
GitBlog/├── .git/ <-- 必须保留,连接远程仓库├── node_modules/ <-- 需清理├── source/ <-- 核心内容,需备份│ └── _posts/ <-- 所有文章 (.md)├── themes/ <-- 需清理├── _config.yml <-- 需清理└── package.json <-- 需清理3. 实战演练:五步完成「换脑」手术
Step 1: 备份文章源码 (资产保全)
在进行任何删除操作前,先把文章拷贝到安全的地方:
# 假设你当前在父目录mkdir -p ./temp_posts && cp -r ./GitBlog/source/_posts/* ./temp_posts/Step 2: 清理旧引擎 (暴力拆解)
进入项目目录,除了 .git 文件夹,清理其余所有 Hexo 相关文件:
cd ~/obsidian_vault/GitBlog# 慎重:确保你已经完成了上一步的备份!rm -rf source themes scaffolds _config.yml _config.butterfly.yml package.json package-lock.json node_modules db.jsonStep 3: 初始化 Astro (旁路注入)
由于 Astro 脚本默认不接受非空目录,我们需要先在一个临时文件夹里初始化,再搬运回来:
# 1. 回到父目录,在临时文件夹里初始化 Astro Blog 模板cd ~/obsidian_vaultnpm create astro@latest ./astro-temp -- --template blog --no-git --no-install
# 2. 将临时文件夹里的所有文件(包含隐藏文件)拷贝回 GitBlogcp -r ./astro-temp/.* ./GitBlog/cp -rn ./astro-temp/ ./GitBlog/
# 3. 删除临时文件夹rm -rf ./astro-tempStep 4: 适配 Front Matter & 搬回文章
Astro 默认的文章路径在 src/content/blog/。
- 搬回文章:
Terminal window mkdir -p GitBlog/src/content/blog/mv ../temp_posts/* GitBlog/src/content/blog/ - 适配 Config (zod schema):
Hexo 的
date格式和自定义字段(如tags,categories,updated,abbrlink)会让 Astro 报错。你需要修改src/content/config.ts来兼容它们:const blog = defineCollection({type: 'content',schema: z.object({title: z.string(),description: z.string().optional(),// 关键:将 Hexo 的日期字符串强制转换为 Date 对象pubDate: z.coerce.date(),updatedDate: z.coerce.date().optional(),heroImage: z.string().optional(),// 添加 Hexo 自定义字段tags: z.array(z.string()).optional(),categories: z.array(z.string()).optional(),abbrlink: z.string().optional(),}),});
Step 5: 本地预览与验证
cd GitBlognpm installnpm run dev访问 http://localhost:4321/,你会看到一个全新的、速度极快的 Astro 博客,而且你的旧文章都在!
4. 云端 CI/CD 换脑:GitHub Actions 适配
由于引擎更换,原本的 deploy.yml 需要彻底重写。Astro 的编译产物在 dist/,我们需要用 npm run build 替换 hexo g。
全新的 .github/workflows/deploy.yml:
name: Astro Auto Deploy
on: push: branches: - main
env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs: build: runs-on: ubuntu-latest steps: - name: Checkout source uses: actions/checkout@v4 with: submodules: true
- name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '24' cache: 'npm'
- name: Install & Build run: | npm install npm run build
- name: Configure SSH env: SSH_ID_RSA: ${{ secrets.HEXO_DEPLOY_PRI }} run: | mkdir -p ~/.ssh/ echo "$SSH_ID_RSA" > ~/.ssh/id_rsa chmod 600 ~/.ssh/id_rsa ssh-keyscan github.com >> ~/.ssh/known_hosts
- name: Deploy to Private Static Repo run: | # 进入 Astro 的构建产物目录 cd dist # 初始化临时 Git 环境并推送到静态私有仓库 git init git config --global user.name "your_username" git config --global user.email "your_email@example.com" git remote add origin git@github.com:yourname/yourname.github.io.git git checkout -b main git add . git commit -m "Rendered by Astro" # 强制覆盖,确保结构纯净 git push -f origin main注意: Cloudflare Pages 无需做任何修改。它只管监听静态仓库
yourname.github.io,无论是 Hexo 推送的public还是 Astro 推送的dist,对于 Cloudflare 来说,它只看.html文件。
5. 扫尾工作:仓库改名与 Obsidian 优化
为了更清晰地表达,我将远程源码仓库改名为 static-blog-source。
5.1 本地与 Submodule 同步
# 1. 更新本地 Git 远程地址cd GitBloggit remote set-url origin git@github.com:yourname/static-blog-source.git
# 2. 回到父目录 (Obsidian 主库),同步子模块路径cd ..# 慎重:确保你已经在 GitHub 网页端完成了改名操作git submodule sync5.2 Obsidian 侧边栏正则过滤 (File Explorer++)
由于 Astro 的目录结构复杂,我们需要更新正则过滤,让侧边栏只显示文章目录: Hide Filter:
^GitBlog/(?!(src/|src$)).*|^GitBlog/src/(?!(content/|content$)).*|^GitBlog/src/content/(?!(blog/|blog$)).*6. 总结
成功