路由与页面结构
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 的约定式文件系统路由:
- 构建期:Astro 扫描
src/pages/目录,目录中的每个.astro/.mdx文件按其相对路径生成一个静态页面;astro.config.mjs中output: "static"明确了静态输出模式,trailingSlash: "always"强制所有生成 URL 以/结尾。 - 链接规范化:内容中的内部链接由
rehype-content-links与remark-wiki-link等插件在构建期统一处理(例如 wiki 风格双链[[...]]被解析为站内链接)。 - 运行期:
@swup/astro集成在浏览器端拦截站内导航,fetch 目标页面的完整 HTML 后仅替换主内容区域,从而获得 SPA 式的页面切换体验,同时保留纯静态部署的简单性。
这种"静态生成 + 客户端增强"的组合是该主题的核心设计取舍:部署目标可以是任意静态托管(无需 Node 服务器),同时用户体验接近 SPA。
Architecture
下图展示路由与页面结构在各层之间的真实依赖与数据流。所有节点均对应仓库中已验证存在的文件/模块:
分层说明:
- 配置层:
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)
以下摘录是路由与页面结构最核心的框架级配置:
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 顶部并未硬编码任何站点信息,而是从主题自身的配置模块导入:
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 配置文件中几十个集成项的排列顺序。
同一文件顶部还引入了完整的构建插件链,其中与"页面间互链"(路由的用户可见面)相关的包括:
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 引入客户端路由增强:
import swup from "@swup/astro";Source: astro.config.mjs
swup 的职责是运行期行为:拦截对站内 URL 的点击,fetch 目标页的完整 HTML,仅替换主内容容器并播放过渡动画。由于每个路由都有完整静态 HTML(output: "static" 的直接收益),这种增强不需要任何服务端配合。
一次页面导航的完整流程
要点:构建期决定"有哪些路由、URL 长什么样";运行期 swup 只决定"切换体验"。二者解耦意味着:即使浏览器不支持 JS 或 swup 初始化失败,普通 <a> 跳转依然可达每一个静态路由——这是渐进增强(progressive enhancement)路线在路由层的体现。
Configuration Options
以下为与本主题直接相关的配置项(均来自 astro.config.mjs 与其引用的配置模块):
| 配置项 | 类型 | 默认值 / 取值 | 说明 |
|---|---|---|---|
site | string | 取自 siteConfig.siteURL | 站点绝对 URL 基准,影响 canonical/sitemap/RSS 中的绝对地址 |
base | string | "/" | 部署子路径前缀;部署到子目录时需同步修改 |
trailingSlash | string | "always" | 强制 URL 以 / 结尾,与链接插件输出保持一致 |
output | string | "static" | 纯静态输出,所有路由构建期生成 |
compressHTML | boolean | true | 压缩生成的 HTML |
server.port | number | 3000 | 本地开发服务器端口,不影响生产路由 |
permalinkConfig | object | 来自 src/config/index.ts | 内容页永久链接结构(文章 URL 层级/slug 规则) |
siteConfig.siteURL | string | 见 src/config/index.ts | site 的实际数据源 |
注:
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指向最终公开域名。
Related Links
- astro.config.mjs — 路由与页面结构的核心框架配置(本页全部配置证据来源)
- src/config/index.ts —
siteConfig/permalinkConfig等配置对象的定义处 - src/plugins/rehype-content-links.mjs — 站内链接统一处理插件
- src/plugins/remark-wiki-link.mjs — wiki 双链语法转站内链接插件
- pagefind.yml — 静态页面的搜索索引配置(路由集合的下游产物)
- 兄弟页面:布局与组件层级、Markdown 渲染管线、站点配置(见本目录其他页面)