用 Github Action,让一个网站拥有两种架构
用 Github Action,让一个网站拥有两种架构
背景
一个站点同时使用 Astro 和 Hexo 两个静态站点生成器,并非主流做法。但只要两者的输出路径不冲突,完全可以合并到同一个 GitHub Pages 部署中。本文记录一种可行方案:Astro 作为主站,Hexo 挂载在 /blog 子路径,通过 GitHub Actions 完成全部构建与部署,最终发布在自定义域名下。
目标
- 主站使用 Astro,部署在
https://e-2.top/ - 博客使用 Hexo,部署在
https://e-2.top/blog/ - 两个项目独立构建,合并后统一发布
- 全流程由 GitHub Actions 自动化,无需本地构建
目录结构
仓库根目录 e2/ 下包含两个独立项目:
1 | e2/ |
技术栈
| 组件 | 技术 |
|---|---|
| 主站框架 | Astro |
| 主站 UI 集成 | React (@astrojs/react) |
| 主站 CSS | Tailwind CSS v4 (@tailwindcss/vite) |
| 博客框架 | Hexo |
| 博客主题 | 通过 npm 安装 |
| CI/CD | GitHub Actions |
| 运行时 | Node.js 24 |
| 托管 | GitHub Pages |
架构设计
合并策略
GitHub Pages 每个仓库只能发布一个站点,因此必须先将两个构建产物合并再上传。合并方式为:以 Astro 的 dist 目录作为发布根,将 Hexo 的 public 目录复制到 dist/blog/ 下。
合并后的发布目录结构:
1 | site-dist/ |
工作流作业划分
工作流包含三个作业:
build-astro:构建 Astro 主站,上传 artifactastro-distbuild-hexo:构建 Hexo 博客,上传 artifacthexo-publicdeploy:下载两个 artifact,合并后发布至 GitHub Pages
deploy 通过 needs 依赖前两个作业,确保合并时两个产物均已完成。
配置文件
Astro 配置
site/astro.config.mjs:
1 | import { defineConfig } from 'astro/config'; |
site 用于生成绝对 URL(canonical、sitemap、RSS 等)。若不设置,这些位置将使用错误的地址。base 显式指定为 /,表示主站部署在根路径。
Hexo 配置
hexo-blog/_config.yml 中与部署相关的字段:
1 | url: https://e-2.top |
root 必须以 / 结尾。若写成 /blog,拼接出的资源路径会缺少分隔符,导致子路径下的 CSS、JS 请求 404。
GitHub Actions 工作流
.github/workflows/deploy.yml:
1 | name: Deploy Astro + Hexo to Pages |
关键步骤说明
分离构建:build-astro 与 build-hexo 是两个独立作业,并行执行,互不干扰。每个作业只检出仓库并安装自身依赖。
缓存:两个作业通过 cache-dependency-path 分别缓存各自的 package-lock.json,避免相互失效。
合并:deploy 作业下载两个 artifact 后,将 Hexo 产物复制到 site-dist/blog/。随后删除 Hexo 可能生成的 CNAME,避免覆盖主域;再写入主域的 CNAME;最后创建 .nojekyll,防止 GitHub Pages 的 Jekyll 处理以下划线开头的目录。
发布:actions/upload-pages-artifact 上传合并后的 site-dist,actions/deploy-pages 完成发布。concurrency 组 pages 保证同时只有一个部署任务运行,新的推送会取消进行中的任务。
GitHub Pages 设置
- Settings → Pages → Source 选择 GitHub Actions
- Custom domain 填写
e-2.top - DNS 校验通过后启用 Enforce HTTPS
DNS 记录
| 类型 | 主机记录 | 值 |
|---|---|---|
| A | @ |
185.199.108.153 |
| A | @ |
185.199.109.153 |
| A | @ |
185.199.110.153 |
| A | @ |
185.199.111.153 |
| CNAME | www |
e-2.top(可选) |
若使用 Cloudflare 等 DNS 服务,所有记录需设为 DNS only(关闭代理),以便 GitHub 验证域名并签发证书。
注意事项
package-lock.json 必须提交。两个子项目的 lock 文件若缺失,npm ci 会失败。
Hexo 主题配置文件需提交。通过 npm 安装的主题,其自定义配置通常位于 hexo-blog/_config.<theme>.yml,若不提交,CI 构建将使用主题默认配置,本地与线上表现不一致。
Astro 不应生成 /blog 路由。若 site/src/pages/ 下存在 blog.astro 或 blog/ 目录,会与 Hexo 子路径冲突。内容集合(如 src/content/blog/)不生成路由,不影响。
本地预览合并结果。在本地分别执行两个项目的构建,手动复制合并到同一目录后,用 npx serve 等静态服务器预览,可提前发现路径问题。
Node 版本。工作流指定 Node 24。Astro 6 要求 Node >= 22.12.0,Hexo 对 Node 24 兼容。
总结
该方案的核心在于:两个静态站点生成器分别构建、分别上传 artifact,在部署阶段合并为单一目录树,再由 GitHub Pages 统一发布。合并点位于构建产物层面,而非源码层面,因此两个项目可以各自独立演进,互不感知对方的存在。子路径部署的关键在于 Hexo 的 root 配置与合并时的目录对齐,两者一致即可避免资源路径错误。
项目已开源:https://github.com/2025studentdev/e2
(部分AI生成)