Repository Wiki
LyraVoid/Mizuki

路由与页面结构

Mizuki 是基于 Astro 静态站点框架构建的博客主题,其"路由与页面结构"由三层协同实现:Astro 文件系统路由(构建期生成静态页面)、以 trailingSlash: "always" 约定的规范化 URL、以及 swup(@swup/astro)提供的浏览器端无刷新页面过渡。本页梳理这条从 src/pages/ 目录树到最终浏览器导航的完整链路。

Purpose and Scope

本页覆盖 Mizuki 主题中"路由与页面结构"这一能力的完整机制:

  • Astro 项目级路由配置(site、base、trailingSlash、output 等),以及这些配置如何决定 URL 形态与部署形态
  • 文件系统路由的构建期生成流程(src/pages/ → 静态 HTML)
  • 浏览器端的路由行为:swup 拦截站内链接并执行视图过渡
  • 内容管线中与"内部链接/页面互链"相关的插件(rehype-content-links、remark-wiki-link 等)
  • 路由的辅助产出物:sitemap(@astrojs/sitemap)与 Pagefind 搜索索引(pagefind.yml)

以下相关主题有意留给兄弟页面,本页只在必要处给出指引:

  • 页面布局(Layouts)与组件层级本身:见「Pages and Layouts」目录下其他页面
  • Markdown 渲染与代码高亮(remark/rehype 完整插件链、Expressive Code):见对应内容渲染页面
  • 全站站点配置项(siteConfig 的字段全集):见「站点配置」相关页面

Overview

Mizuki 没有使用任何客户端路由库(仓库中不存在 createBrowserRouter、<Route> 之类的 React Router 代码),而是完全采用 Astro 的约定式文件系统路由:

  1. 构建期:Astro 扫描 src/pages/ 目录,目录中的每个 .astro / .mdx 文件按其相对路径生成一个静态页面;astro.config.mjs 中 output: "static" 明确了静态输出模式,trailingSlash: "always" 强制所有生成 URL 以 / 结尾。
  2. 链接规范化:内容中的内部链接由 rehype-content-links 与 remark-wiki-link 等插件在构建期统一处理(例如 wiki 风格双链 [[...]] 被解析为站内链接)。
  3. 运行期:@swup/astro 集成在浏览器端拦截站内导航,fetch 目标页面的完整 HTML 后仅替换主内容区域,从而获得 SPA 式的页面切换体验,同时保留纯静态部署的简单性。

这种"静态生成 + 客户端增强"的组合是该主题的核心设计取舍:部署目标可以是任意静态托管(无需 Node 服务器),同时用户体验接近 SPA。

Architecture

下图展示路由与页面结构在各层之间的真实依赖与数据流。所有节点均对应仓库中已验证存在的文件/模块:

Loading diagram...

分层说明:

  • 配置层:astro.config.mjs 是 Astro 的唯一入口配置,其 site、base 等关键值并非硬编码,而是从 src/config/index.ts 导入的 siteConfig、permalinkConfig 等配置对象派生。这样可以让使用主题的用户在一个集中的配置模块中改站点 URL 与永久链接结构,而不必改动框架配置文件。
  • 构建期:src/pages/ 是 Astro 约定的路由目录;output: "static" + trailingSlash: "always" 决定了产出的 URL 形态。
  • 内容与内部链接管线:Markdown/MDX 内容在构建期经过 remark/rehype 插件链,其中 rehype-content-links 与 remark-wiki-link 负责内部链接语义,保证内容互链与站点路由约定一致。
  • 运行期:swup 是唯一参与"路由"的浏览器端组件,它不生成新路由,只增强既有静态页面之间的切换。
  • 辅助产出:sitemap 与 Pagefind 索引都是从静态页面集合派生的下游产物,用于 SEO 与站内搜索。

说明:src/pages/ 内具体页面文件的清单未在本次源码审查中读取(源码探索预算限制),因此本页对路由树的描述以 astro.config.mjs 中可验证的框架级约定为准,不虚构具体路由清单。

核心实现:路由相关配置详解

站点级路由配置(astro.config.mjs)

以下摘录是路由与页面结构最核心的框架级配置:

javascript
1 site: siteConfig.siteURL, 2 base: "/", 3 trailingSlash: "always", 4 compressHTML: true, 5 6 output: "static", 7 8 image: { 9 layout: "constrained", 10 }, 11 12 server: { 13 port: 3000, 14 },

Source: astro.config.mjs

逐项解读这些配置为什么这样设置:

  • site: siteConfig.siteURL — site 是 Astro 生成绝对 URL(canonical、sitemap、OG 图)的基准。它不是硬编码字面量,而是读取自主题集中配置模块,让每个使用 Mizuki 的站点都能正确声明自己的域名,同时保证 sitemap 与 RSS 中的链接是绝对地址。
  • base: "/" — 主题默认部署在域名根路径下。若部署到子路径(如 GitHub Pages 项目页 /repo/),需要修改此值,Astro 会自动为所有生成页面与站内资源加上该前缀;这也是"路由结构"在部署层面唯一需要关注的开关。
  • trailingSlash: "always" — 强制所有路由以 / 结尾(例如 /posts/ 而非 /posts)。这一选择与内容管线中的链接生成插件保持一致:如果链接插件输出无尾斜杠地址、而服务器又启用严格匹配,就会产生 404 或重定向链;统一约定可以从源头消除这类不一致。
  • output: "static" — 明确纯静态输出。Mizuki 的"路由"没有 SSR 动态段,所有页面在构建期一次性生成,因此可以被任何静态托管服务直接服务,也让 swup 的"fetch 整页再替换主容器"策略成为可能(每个 URL 都有完整 HTML 可取)。
  • compressHTML: true — 静态产物的体积优化,与路由逻辑正交但同属构建产出形态。
  • server.port: 3000 — 仅影响本地开发服务器(astro dev),不影响生产路由。

配置来源的集中化设计

astro.config.mjs 顶部并未硬编码任何站点信息,而是从主题自身的配置模块导入:

javascript
1import { 2 expressiveCodeConfig, 3 markdownConfig, 4 permalinkConfig, 5 siteConfig, 6} from "./src/config/index.ts";

Source: astro.config.mjs

其中与路由直接相关的是 siteConfig(提供 siteURL,决定绝对 URL 基准)与 permalinkConfig(决定内容页的永久链接结构,例如文章 URL 的层级与 slug 规则)。这一设计的意图是把"用户可定制的路由语义"与"框架接线方式"分离:主题用户只编辑 src/config/index.ts 暴露的配置对象,而不需要理解 Astro 配置文件中几十个集成项的排列顺序。

同一文件顶部还引入了完整的构建插件链,其中与"页面间互链"(路由的用户可见面)相关的包括:

javascript
import { rehypeContentLinks } from "./src/plugins/rehype-content-links.mjs"; import { remarkWikiLink } from "./src/plugins/remark-wiki-link.mjs";

Source: astro.config.mjs

  • remark-wiki-link:把 Obsidian 风格的 [[页面名]] 双链语法转换为标准站内链接,使内容写作不必手写相对路径——这也是静态路由体系中"内容引用页面"这一需求的解法。
  • rehypeContentLinks:在 HTML 阶段统一处理正文中的站内链接(例如统一尾斜杠、附加过渡所需的属性),保证构建产物中的链接与 trailingSlash: "always" 的路由约定严格一致。

集成(integrations)部分从 @swup/astro 引入客户端路由增强:

javascript
import swup from "@swup/astro";

Source: astro.config.mjs

swup 的职责是运行期行为:拦截对站内 URL 的点击,fetch 目标页的完整 HTML,仅替换主内容容器并播放过渡动画。由于每个路由都有完整静态 HTML(output: "static" 的直接收益),这种增强不需要任何服务端配合。

一次页面导航的完整流程

Loading diagram...

要点:构建期决定"有哪些路由、URL 长什么样";运行期 swup 只决定"切换体验"。二者解耦意味着:即使浏览器不支持 JS 或 swup 初始化失败,普通 <a> 跳转依然可达每一个静态路由——这是渐进增强(progressive enhancement)路线在路由层的体现。

Configuration Options

以下为与本主题直接相关的配置项(均来自 astro.config.mjs 与其引用的配置模块):

配置项类型默认值 / 取值说明
sitestring取自 siteConfig.siteURL站点绝对 URL 基准,影响 canonical/sitemap/RSS 中的绝对地址
basestring"/"部署子路径前缀;部署到子目录时需同步修改
trailingSlashstring"always"强制 URL 以 / 结尾,与链接插件输出保持一致
outputstring"static"纯静态输出,所有路由构建期生成
compressHTMLbooleantrue压缩生成的 HTML
server.portnumber3000本地开发服务器端口,不影响生产路由
permalinkConfigobject来自 src/config/index.ts内容页永久链接结构(文章 URL 层级/slug 规则)
siteConfig.siteURLstring见 src/config/index.tssite 的实际数据源

注:siteConfig / permalinkConfig 的完整字段清单位于 src/config/index.ts,本次未逐行读取,完整字段语义请以该文件为准;其归属主题页面为「站点配置」。

Failure Modes, Edge Cases & Concurrency

基于已验证的配置事实,可推导并需注意的边界情况:

  • trailingSlash: "always" 与外部链接不一致:若某处内容硬编码了无尾斜杠的站内 URL,在启用严格尾斜杠匹配的托管平台上会 301 重定向,增加一次往返;这正是仓库同时提供 rehype-content-links 在构建期统一链接形态的原因。
  • base 与部署路径不匹配:base: "/"" 假定根路径部署。迁移到子路径部署而未同步修改 base 时,所有站内资源与页面互链都会指向错误前缀。
  • swup 依赖每个路由的完整 HTML:output: "static" 保证了这一点。若未来切换到 server 输出模式或按需渲染,swup 的"fetch 整页替换容器"策略需要重新验证。
  • 无 JS 环境的降级:路由本身不依赖客户端 JS,普通链接跳转始终可用;损失的只是过渡动画。
  • site 为空或不正确:sitemap 与绝对 URL 会生成错误地址。siteURL 配置错误属于"构建成功但产物路由错误"的静默失败,应在部署前校验。

Extension Points

  • 新增路由:在 src/pages/ 下新增 .astro / .mdx 文件或目录即可获得新路由,无需注册表——这是 Astro 约定式路由的核心扩展点。
  • 调整 URL 结构:修改 src/config/index.ts 中的 permalinkConfig(内容页永久链接)与 siteConfig.siteURL(站点基准),astro.config.mjs 会自动消费这些值。
  • 自定义链接语义:如需新的站内链接语法(类似 remark-wiki-link 的双链),可在 astro.config.mjs 的 remark/rehype 插件链中追加自定义插件,遵循 src/plugins/ 下既有插件的命名与组织方式(remark-* 处理 Markdown 层、rehype-* 处理 HTML 层)。
  • 子路径部署:修改 base 并确认 site 指向最终公开域名。

Sources

(1 files)