本项目的配置分散在 6 个文件,本文逐一给出参数表。

文件定位谁需要改
src/site.config.ts站点唯一配置入口:站点信息、导航数据、社交、友链、插件开关、音乐播放器每个使用者都必须改
astro.config.mjs框架级:markdown 链、Vite 构建、Swup、sitemap、站点 URL改渲染/构建行为时
src/content.config.ts文章 frontmatter 的 Zod schema加自定义 frontmatter 字段时
tsconfig.jsonTypeScript 与路径别名加别名时
biome.json代码风格与 lint团队风格统一时
pagefind.yml搜索索引排除选择器不想被搜到的区域

1. src/site.config.ts 顶部导出的类型

改配置前先认识这三个类型(源码第 1–22 行):

ts
1234567891011121314151617
export interface SocialLink {
  platform: string   // 平台标识,见#2.9 支持列表
  url: string        // 链接地址
}

export interface FriendLinkRaw {
  url: string        // 必填,无协议会自动补 https://
  name?: string      // 可选,缺省取域名
  desc?: string      // 可选,缺省取域名
  icon?: string      // 可选,以 /friends/ 开头的 public 路径
}

export interface MusicTrack {
  title: string      // 必填,歌曲标题
  src: string        // 必填,public/ 下的静态路径(以 / 开头)或完整 http(s) URL
  cover?: string     // 可选,留空时按钮显示音符图标或从音频元数据提取
}

2. siteConfig 字段逐项说明

使用方式

siteConfig 是一个 export const 普通对象,不是 defineConfig 包装的。它被 astro.config.mjs(构建期读取 URL 与默认语言)和大量组件 import 使用。

改动后需要重启 dev server(astro.config.mjs 在启动时读取它)。纯组件消费的字段在 HMR 下可直接生效。

2.1 url — 站点地址

项值
类型string
默认值'https://citrusgrid.pages.dev'
必填是(部署前必须改成自己的域名)

影响范围(改错了会连带出问题,请逐项检查):

消费者用途
astro.config.mjs → siteAstro 的 canonical 基准、sitemap 生成
BaseLayout.astro<link rel="canonical">、og:url
src/pages/rss.xml.tsRSS 的 site 与条目绝对链接
SiteFooter.astro版权作者名的跳转链接
src/lib/md/rehypeExternalLinks.ts判断「外链」的基准 host(同 host 不加 target="_blank")

尾斜杠

src/pages/rss.xml.ts:8 确实会 site.replace(/\/+$/, '') 去尾部斜杠,但 canonical 的 new URL(Astro.url.pathname, Astro.site) 在 src/layouts/BaseLayout.astro:36,依赖标准 URL 解析。建议不要在 url 末尾加 /。

2.2 站点信息三件套

字段类型默认值用途
titlestring'CitrusGrid'<title> 前缀、头部 Logo 旁文字、OG og:site_name、JSON-LD publisher
subtitlestring'A pure static Astro blog theme'首页(无 title prop 时)<title> = {title} - {subtitle}
descriptionstring'这是一个基于 Astro 架构和 CitrusGrid主题的轻量级静态博客。'默认 meta description、OG/Twitter、JSON-LD、首页名片简介(ProfileCard 的 .bio)

description 身兼两职:既是 SEO 描述,又是首页名片上作者名下方的那行简介。想分开,需在 ProfileCard.astro 里改用独立字段。

字段类型默认值用途
avatarstring'/avatar.webp'首页名片头像(64×64 圆形,object-fit: cover)
logostring'/logo.webp'头部 Logo(28×28)、<link rel="icon">、OG 图片默认值、JSON-LD publisher logo

两者都以 / 开头,指向 public/ 下的文件。换图只需替换 public/avatar.webp 与 public/logo.webp,无需改配置。

BaseLayout 的 <link rel="icon" type="image/webp" href="/logo.webp"> 是硬编码的 /logo.webp,不是 siteConfig.logo。若改 logo 路径,favicon 也要同步改 BaseLayout.astro。

2.4 author

项值
类型string
默认值'example name'

用途:页脚版权署名、首页名片用户名、JSON-LD author.name、文章页版权块的 {author}、ProfileCard 头像 alt。

2.5 defaultLang — 默认语言

项值
类型'zh' | 'ja' | 'en'
默认值'zh'

影响范围:

消费者作用
src/lib/url.ts 的 defaultLang(src/i18n/ui.ts 转导出)全站取词的默认语言
astro.config.mjs脚注标题(footnoteLabel)取该语言的 post.footnotes
src/pages/rss.xml.ts<language>{defaultLang}</language>
所有路由目前所有 src/pages/*.astro 都 const lang = defaultLang,只构建默认语言页面

详见 07-页面与路由.md#5。

非法值直接报错

site.config.ts 末尾会调用 validateSiteConfig(siteConfig)(实现见 src/lib/siteConfigGuard.ts):defaultLang 不属于 zh / ja / en 时抛出 Error,dev 启动与构建都会立即中断,不再依赖 as 强转静默通过。提示为英文(示例:`defaultLang` must be one of "zh" / "ja" / "en", received "fr".),源码中每条英文提示上方都紧邻一行中文译注。

2.6 defaultTheme — 默认主题

项值
类型'auto' | 'light' | 'dark'
默认值'auto'
取值行为
'auto'跟随系统 prefers-color-scheme,且系统切换时实时跟随
'light'默认亮色,用户手动切换后写入 localStorage.themeMode 覆盖
'dark'默认暗色,同上

渲染到 <html data-default-theme="…">,由 stores/theme.ts 的 defaultMode() 读取。详见 03-主题与样式定制.md#6。

2.7 postsPerPage — 首页每页文章数

项值
类型number(源码未做校验,建议正整数)
默认值10

消费者:

位置逻辑
src/pages/index.astroall.slice(0, perPage),totalPages = Math.ceil(all.length / perPage) || 1
src/pages/[page].astropaginate(posts, { pageSize: siteConfig.postsPerPage }),再 .filter(p => Number(p.params.page) > 1)(第 1 页由 index.astro 负责,避免重复生成)

改小这个值会新增大量页面

postsPerPage 从 10 改成 5,文章数 100 时会从 10 页变成 20 页,构建时间近似线性增长。

2.8 socials — 社交按钮

项值
类型SocialLink[]
默认值[{ platform: 'github', url: 'https://github.com' }, { platform: 'rss', url: '/rss.xml' }]
隐藏方式设为 []
支持值图标hover 品牌色
githubGitHub#24292e
twitter / xTwitter#1da1f2
linkedinLinkedIn#0a66c2
youtubeYouTube#ff0000
instagramInstagram#e4405f
facebookFacebook#1877f2
devtoDev.to#0a0a0a
medium通用链接图标#000000
rssRSS#f26522
email / mail邮件var(--wp-accent)
website / blog网页var(--wp-accent)
其他任意字符串通用链接图标 mdi-link-variantvar(--wp-accent)

示例:

ts
1234567
socials: [
  { platform: 'github',   url: 'https://github.com/yourname' },
  { platform: 'twitter',  url: 'https://twitter.com/yourname' },
  { platform: 'email',    url: 'mailto:you@example.com' },
  { platform: 'rss',      url: '/rss.xml' },     // 站内路径,不加 target=_blank
  { platform: 'bilibili', url: 'https://space.bilibili.com/xxx' },  // 未内置,用通用图标 + 主题色
] as SocialLink[],

平台名文本:由 platform 首字母大写生成(github → Github),用作按钮的 aria-label / title(按钮为 42×42 纯图标方块、贴在名片正下方)。想改提示文案,需要在 ProfileCard.astro 中改用固定映射或增加 label 字段。

支持列表的 platform 匹配是大小写不敏感的(内部 toLowerCase())。

2.9 statsScript — 统计插件

项值
类型string(对应 src/stats/ 下的文件名,不含 .ts)
默认值'random-visitor'
停用设为 ''(空字符串)
取值效果
''完全不注入统计脚本,ProfileCard 与文章页不渲染 PV/UV 挂载点
'random-visitor'内置的测试用插件:随机生成数字,便于本地调整排版
'visitor-stats'内置的正式插件,需自行在 Cloudflare Worker 部署统计服务
自定义名在 src/stats/ 新建同名 .ts 并实现契约

关键行为:统计脚本仅在构建产物(生产环境)中注入。BaseLayout.astro 的条件是:

astro
1
data-stats-script={(siteConfig.statsScript && import.meta.env.PROD ? siteConfig.statsScript : undefined)}

以及

astro
1
{siteConfig.statsScript && import.meta.env.PROD && <script>import '@/stats/client'</script>}

挂载点的渲染条件:只有 Boolean(siteConfig.statsScript),不带 PROD 判断(ProfileCard.astro:40、PostCard.astro:28、PostPage.astro:40)。因此:

环境挂载点(- 占位与「次 / 人」单位)客户端脚本<html data-stats-script>
pnpm dev✅ 渲染(只要 statsScript 非空)❌ 不注入❌ 不设置
pnpm build✅ 渲染✅ 注入✅ 设置

也就是说 dev 下能看到 PV/UV 的位置,但数字永远是 -,也不会发出任何统计请求。要验证真实数字必须 pnpm build && pnpm preview。只有把 statsScript 留空('')时挂载点才完全不渲染。

默认是测试插件。

'random-visitor' 会显示随机数字,上线前请改成正式插件或留空。

详细契约见 08-插件系统.md#3。

2.10 friends — 友链

项值
类型FriendLinkRaw[]
默认值一条示例 { url: 'https://example.com', name: 'test', desc: 'a desc', icon: '/friends/logo.webp' }
空数组效果显示空状态插画页(不是隐藏友链入口)
字段必填说明
url是无 http(s):// 前缀会自动补 https://
name否缺省取域名(去 www.)
desc否缺省取域名
icon否放 public/friends/ 下,引用写 /friends/文件名.后缀;缺省显示首字母方块

示例:

ts
12345
friends: [
  { url: 'https://astro.build', name: 'Astro', desc: 'The web framework for content-driven websites', icon: '/friends/astro.webp' },
  { url: 'example.org',        name: '示例站' },                    // 自动补 https://,无图标
  { url: 'https://foo.dev' },                                      // 名称/描述都取域名 foo.dev
] as FriendLinkRaw[],

2.11 commentScript — 评论插件

项值
类型string(对应 src/comments/ 下的文件名,不含 .ts)
默认值''(默认关闭评论)
启用内置 utterances'utterances'

启用后还需编辑 src/comments/utterances.ts 的 config.repo 填写 GitHub 仓库,否则适配器会抛错并隐藏整个评论区。

详细契约见 08-插件系统.md#2。

2.12 autoUpdatePostUpdated — 自动写 updated

项值
类型boolean
默认值false(V1.0.5 起改为关闭)
取值行为
true每次 buildStart(构建时、dev 启动时)按文章文件 mtime 回写 frontmatter 的 updated 字段
false完全不执行 updatePostUpdated 插件(astro.config.mjs 里 updatePostUpdated({ enabled: siteConfig.autoUpdatePostUpdated }) 会返回 null,Vite 忽略该插件)

为什么默认关闭?

该功能会在构建时改写你的 markdown 源文件。若你习惯「先 build 再 commit」,开启后会把时间戳一起提交;若你在 CI 上构建,还可能因只读文件系统或权限导致构建失败。建议本地按需开启。

相关注意点(更新说明.md 原文提示):

  • pnpm format-post-meta(元数据排序)仍是手动执行,建议先排版再构建;
  • 建议先 pnpm build 再 git commit,让 slug/updated 的改动一次性提交完。

2.13 musicPlayer — 右下角磁铁音乐播放器

字段类型默认值说明
enabledbooleantrue是否渲染整个播放器
playlistMusicTrack[][]显式播放列表;空数组 = 构建期自动扫描 public/music/

playlist 为空时的自动扫描规则:

环节行为
扫描目录public/music/(不存在时返回 [],不报错)
识别扩展名.flac .mp3 .m4a .ogg .wav .opus .aac .webm
排序localeCompare(a, b, 'zh'),即按中文文件名排序
title去扩展名的文件名
src/music/${encodeURIComponent(文件名)}(中文会自动 URL 编码)
cover不设置 → 客户端从音频元数据提取(FLAC PICTURE / MP3 ID3v2 APIC,读文件头 2MB)

显式指定示例:

ts
12345678
musicPlayer: {
  enabled: true,
  playlist: [
    { title: '预言 Prophecy', src: '/music/预言 Prophecy.flac', cover: '/music/prophecy-cover.webp' },
    { title: '闪亮',           src: '/music/闪亮.flac' },   // 封面从元数据自动提取
    { title: '原色',           src: '/music/原色.flac' },
  ] as MusicTrack[],
},

加歌最省事的做法:

直接把音频文件丢进 public/music/,保持 playlist: [],重新构建即可。标题就是文件名(所以文件名即显示名)。

2.14 nav — 顶栏导航

项值
类型string[](站内路径)
默认值['/archive', '/categories', '/tags', '/series', '/friends', '/about']

SiteHeader.astro 按数组顺序渲染顶栏项;首页 / 固定第一位、不可移除,不要写进数组(写了也会被过滤)。数组去重,未在组件 NAV_DEFS 注册表登记的 path 会被忽略(新增自定义页面需先在 NAV_DEFS 登记词条 key 与图标)。空数组 [] 则顶栏只剩首页一项。缺失时回退为空(仅首页)并警告:nav 被删除或写成非字符串数组时,src/lib/siteConfigGuard.ts 的 validateSiteConfig() 会输出英文 console.warn(源码中附中文译注),顶栏按空数组渲染,构建不会中断。详见 02-组件说明.md#31-siteheaderastro。

2.15 pet — 左下角宠物挂件

字段类型默认值说明
enabledbooleantrue是否渲染左下角宠物(视线跟随 / 眨眼 / 休眠 / 滑出)以及名片上的「唤回宠物」按钮
ts
123
pet: {
  enabled: true,
},

关闭方式:把 enabled 改为 false,Pet.astro 即不输出任何 DOM(是「不渲染」而非「隐藏」),ProfileCard.astro 里那颗唤回按钮也不会渲染。

开启后多出的交互(细节见 02-组件说明.md#35-petastro):

交互说明
长按 550ms弹出「请去休息」气泡(文案取自 i18n 的 pet.dialogLabel / pet.title / pet.desc / pet.confirm),气泡里只有「关闭」一个按钮
关闭后在 localStorage 写入到期时间戳 petClosedUntil(24 小时),宠物按方格消解退场并整块隐藏;这段时间刷新页面也不会出现
唤回首页名片社交条上出现「唤回宠物」按钮(词条 pet.restore),点一下即清掉时间戳,宠物以方格聚合重新出现;时间戳自然过期后刷新同样会回来

与 nav / musicPlayer 不同,组件读取用的是可选链 siteConfig.pet?.enabled === true,所以整个 pet 字段缺失也不会报错,只是按关闭处理;validatePet() 会在这种「缺失或非布尔」的情况下输出英文 console.warn(提示宠物按关闭处理),不中断构建。字段说明、行为与关闭方法见 02-组件说明.md#35-petastro。

3. astro.config.mjs 参数表

js
123456789
export default defineConfig({
  site,                                        // 来自 siteConfig.url
  server:  { host: '::' },                     // dev 监听所有网卡(IPv6 通配)
  preview: { host: '::' },                     // preview 同上
  build:   { inlineStylesheets: 'always' },    // 所有 CSS 内联进 HTML
  markdown: { ... },                           // 见#3.2
  integrations: [ swup({...}), sitemap() ],    // 见#3.3
  vite: { ... },                               // 见#3.4
})

3.1 顶层选项

选项值说明
sitesiteConfig.urlcanonical / sitemap / RSS 基准
server.host'::'开发服务器监听所有网卡,便于局域网/手机真机调试
preview.host'::'预览服务器同上
build.inlineStylesheets'always'关键 CSS 内联,消除首屏 CSS 请求(代价:HTML 体积增大,多页共享的 CSS 无法复用缓存)

3.2 markdown 配置

js
1234
markdown: {
  syntaxHighlight: false,        // 关闭 Astro 内置 shiki,改用自定义 Prism 构建期高亮
  processor: unified({ ... }),
}
处理器选项值说明
gfmtrueGitHub Flavored Markdown(表格、任务列表、删除线、自动链接)
smartypantsfalse不把直引号转成弯引号
remarkRehype.footnoteLabel按 defaultLang 取 post.footnotes脚注区标题走 i18n(zh「脚注」/ ja / en)
remarkRehype.clobberPrefix'post-'脚注 id 前缀,从默认 user-content- 改为 post-(避免被 GitHub 式清洗规则误伤)

remark 插件链(按顺序):

顺序插件作用
1remarkBreaks单个换行也渲染成 <br>(贴合中文写作习惯)
2remarkEmoji:smile: → 😄
3remarkMath解析 $…$ / $$…$$ 数学公式
4remarkContainers(自定义)解析 :::info / :::tip / :::warning / :::danger / :::details

rehype 插件链(按顺序):

顺序插件作用
1rehypeKatex数学公式 → KaTeX HTML
2rehypeCodeBlock(自定义)<pre><code> → 带语言图标、行号、复制按钮的 .code-block(含 Prism 高亮)
3rehypeImages(自定义)图片包成 .img-frame + a.img-lightbox,注入 LQIP 渐变;首图 loading="eager" fetchpriority="high",其余 lazy
4rehypeRelativeLinks(自定义)./其他.md → /posts/其他-slug/;相对图片 → /content-images/{hash}.ext
5rehypeTableWrap(自定义)表格外包 div.table-wrapper(横向滚动容器)
6rehypeExternalLinks(自定义)站外链接加 target="_blank" rel="noopener noreferrer"
7rehypeSlug标题加 id(TOC 锚点基础)
8rehypeAutolinkHeadings标题尾部追加 # 锚点链接(behavior: 'append',class heading-anchor,aria-label="Heading anchor")

顺序敏感:rehypeKatex 必须在 rehypeSlug 之前(KaTeX 会生成带 id 的元素);rehypeRelativeLinks 必须在 rehypeImages 之后(前者需要处理后者生成的 href)。调整顺序可能破坏功能。

3.3 integrations — Swup 与 Sitemap

Swup 参数:

参数值说明
themefalse不使用 Swup 官方主题,过渡样式自己写在 main.css
animationClass'transition-swup-'动画类前缀,实际用 .transition-swup-fade
containers['#swup-container']只替换这个容器(改这里要同步 BaseLayout 的结构)
smoothScrollingfalse关闭,锚点滚动自行实现(带 80px 偏移):同页目录/标题锚点由 PostPage 处理,跨页锚点由 BaseLayout 接管(见 07-页面与路由.md#84)
cachetrue缓存已访问页面
preload{ hover: true, visible: true }悬停与进入视口时预取
accessibilitytrue无障碍播报
progresstrue顶部进度条(样式见 main.css 的 .swup-progress-bar)
updateHeadtrue换页时更新 <head>(title / meta)
updateBodyClassfalse不替换 body class(避免主题类丢失)
globalInstancetrue挂到 window.swup(SearchModal 与 BaseLayout 依赖此全局实例)
ignore函数见下方规则

ignore 回调规则:

js
1234567
ignore: (url) => {
  if (url.includes('#')) return true                       // 含 # 的一律跳过 Swup:同页锚点由 PostPage、跨页锚点由 BaseLayout 点击委托接管,都不会原生闪现
  const path = new URL(url, 'https://example.com').pathname
  if (/\.(xml|txt|json|pdf|zip|png|jpe?g|webp|gif|svg|ico|avif|woff2?|ttf|eot)$/i.test(path)) return true
  if (/^\/(pagefind|fonts|images)\//.test(path)) return true
  return false
}

Sitemap:sitemap() 无参数,生成 /sitemap-index.xml 与 /sitemap-0.xml。SiteFooter 的 Sitemap 链接硬编码为 /sitemap-index.xml。

3.4 vite 配置

Vite 插件(构建期数据生成):

插件来源作用可调参数
tailwindcss()@tailwindcss/viteTailwind v4 编译—
ensurePostSlugs()scripts/ensure-post-slugs.js补全 slug,写 post-index.json无
generateLqips()scripts/generate-lqips.js图片主色采样环境变量 LQIP_FORCE=1 强制全量重算
updatePostUpdated({ enabled })scripts/update-post-updated.js回写 updatedsiteConfig.autoUpdatePostUpdated

optimizeDeps.include:

js
12345678
[
  'photoswipe', 'photoswipe/lightbox', 'astro/virtual-modules/transitions-*.js',
  // Swup 的 Astro 客户端模块:按需拆成 8 个入口,全部预打包
  '@swup/astro/idle', '@swup/astro/serialise',
  '@swup/astro/client/Swup', '@swup/astro/client/SwupA11yPlugin',
  '@swup/astro/client/SwupHeadPlugin', '@swup/astro/client/SwupProgressPlugin',
  '@swup/astro/client/SwupPreloadPlugin', '@swup/astro/client/SwupScriptsPlugin',
]

预打包这些依赖,避免 dev 首次访问文章页(PhotoSwipe)或首次触发换页(Swup 各插件)时出现「新依赖发现 → 重新预构建 → 页面刷新」。Swup 那 8 项是逐插件列出的,@swup/astro 升级后若入口文件名变化需同步这一份清单。

build 参数:

参数值说明
minify'esbuild'JS 压缩器
esbuildOptions.minifytrue—
esbuildOptions.drop['debugger']移除 debugger 语句
esbuildOptions.pure['console.log', 'console.debug']标记为无副作用,可被摇树移除
cssCodeSplittrueCSS 按 chunk 拆分
cssMinify'lightningcss'用 lightningcss 压缩(比 esbuild 更激进)
assetsInlineLimit4096<4KB 的资源内联为 base64

pure: ['console.log'] 的副作用:

如果你在客户端脚本里用 console.log 调试,生产构建会被移除(console.warn / console.error 保留)。调试请用 pnpm dev。

4. src/content.config.ts — 文章 Schema

ts
12345
const posts = defineCollection({
  loader: glob({ pattern: '**/*.md', base: './src/content/posts' }),
  schema: z.object({ ... }),
})
export const collections = { posts }
frontmatter 字段Zod 类型默认值归一化 / 校验
titlez.string().min(1)—至少 1 字符
slugz.string().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).nullish()—可空;允许小写字母数字与单个连字符分隔
indexz.number().int().min(0).default(0)0非负整数,>0 视为置顶
descriptionz.string().min(1)—至少 1 字符
categoryz.union([z.string(), z.array(z.string())]).default('未分类')'未分类'transform 后只取归一化列表的第 1 项
tagsz.union([z.string(), z.array(z.string())]).default('')''transform 后变成去空、去重(大小写不敏感)的数组
publishedz.coerce.date()—强制转 Date;字符串 YYYY-MM-DD HH:mm:ss 可被解析
updatedz.coerce.date().optional()—可选
draftz.boolean().default(false)false生产构建时 draft: true 的文章被过滤

normalizeList 的行为:(源码第 5–18 行)

ts
12
// 输入 "a, b, a" 或 ['a','b','a']  →  输出 ['a','b']
// 规则:按逗号拆分(字符串时)→ trim → 跳过空值 → 按 toLowerCase() 去重 → 保留原始大小写

所以 tags: [Markdown, markdown] 只会保留第一个 Markdown。

加自定义字段的示例:(例如加一个 cover 封面图字段):

ts
12345
// src/content.config.ts
schema: z.object({
  // ...原有字段
  cover: z.string().optional(),
}),

然后 Post 类型会自动带上 post.data.cover。别忘了同步 scripts/format-post-meta.js 的 ORDER / LAST 数组,否则 pnpm format-post-meta 会把它排到末尾。

5. tsconfig.json

json
12345678910
{
  "extends": "astro/tsconfigs/strict",
  "include": [".astro/types.d.ts", "**/*"],
  "exclude": ["dist", "node_modules"],
  "compilerOptions": {
    "baseUrl": ".",
    "resolveJsonModule": true,
    "paths": { "@/*": ["src/*"] }
  }
}
项说明
extendsAstro 的 strict 预设(比 strictest 宽松,允许 any 推断但不允许隐式 any)
include覆盖全项目(含 scripts/)与 Astro 生成的类型
paths@/* → src/*,全项目统一用 @/ 别名
resolveJsonModule允许 import zhJson from './zh.json'(i18n/ui.ts 与 astro.config.mjs 依赖)

i18n key 的类型安全(T13)

  • src/i18n/ui.ts 从 zh.json 递归派生出点路径联合类型 MessageKey(深度上限 5 层,当前语言包最深 3 层),t(key: MessageKey, params?) 因此能在 pnpm check / pnpm type-check 阶段拦住拼错的键(例如 t('nav.hom') 直接编译报错)。
  • 为让 TS 推导出字面量键,src/env.d.ts 不再 declare module '*.json'(那条声明会把 JSON import 统一成 Record<string, any>);全项目只有 i18n/ui.ts import JSON。
  • 取词未命中时:dev 环境在服务端日志打印 [i18n] missing message: <key> (<lang>.json),生产环境保持静默回退(显示 key 原文),行为与之前一致(构建产物里 dev 告警分支已被消除)。
  • 三份语言包键集合一致性由 pnpm check-i18n(scripts/check-i18n.js)手动校验,不一致时 exit 1 并列出缺失 / 多出的键。

加新别名:

json
1234
"paths": {
  "@/*": ["src/*"],
  "@components/*": ["src/components/*"]
}

astro.config.mjs 不读取 tsconfig.json 的 paths(它是被 Vite 处理的),所以在 astro.config.mjs 里 import 必须用带扩展名的相对路径,例如 ./src/site.config.ts、./src/lib/md/rehypeCodeBlock.ts(源码确实这么写)。

6. biome.json

配置块值说明
vcs.enabledfalse不读取 gitignore
files.ignoreUnknownfalse未知文件类型报错
formatter.indentStyle"space"空格缩进
formatter.indentWidth22 空格
formatter.lineWidth100100 列换行
linter.rules.preset"recommended"推荐规则集
javascript.formatter.quoteStyle"single"单引号
javascript.formatter.semicolons"asNeeded"无多余分号
css.parser.tailwindDirectivestrue必须,否则 Biome 无法解析 @theme / @custom-variant / @import "tailwindcss"
overrides[**/*.astro].linter.rules.correctnessnoUnusedVariables: off,noUnusedImports: offAstro 组件里常有「模板用不到但类型需要的导入」,故关闭

命令对应:

命令实际执行范围
pnpm formatbiome format --write ./src只格式化 src
pnpm lintbiome check --write ./src检查 + 修复 src
pnpm format:allbiome check --write ./src ./scripts ./astro.config.mjs ./biome.json ./package.json ./tsconfig.json全项目

7. pagefind.yml

yaml
12345
exclude_selectors:
  - ".katex"          # KaTeX 渲染出的公式排版节点
  - ".katex-display"  # 块级公式
  - ".code-header"    # 代码块头部(语言标签 + 复制按钮,不应进索引)
  - ".md-toc"         # markdown 内的目录块

7.1 搜索索引的范围控制

机制位置作用
data-pagefind-bodyPostPage.astro 的 .post-content只有该容器内的内容被索引(否则 Pagefind 会索引整个页面,包括导航与页脚)
data-pagefind-filter="tag"文章页的标签链接建立 tag 过滤器(当前 UI 未使用,可用于高级筛选)
exclude_selectorspagefind.yml从索引中剔除指定选择器

常见扩展示例:

yaml
1234567
exclude_selectors:
  - ".katex"
  - ".katex-display"
  - ".code-header"
  - ".md-toc"
  - ".img-frame"        # 图片
  - ".md-container"     # 提示容器整块

加了新选择器要重新构建:

pagefind.yml 只在 postbuild.js 里被读取(pagefind --site dist 会读项目根的 pagefind.yml),改动后必须 pnpm build。

8. 配置文件改动影响速查

改了需要重启 dev?需要重新 build?还需要连带改什么
siteConfig.title / subtitle / description否(组件 HMR)是(部署时)—
siteConfig.url否是RSS、sitemap、canonical 全部重算;astro.config.mjs 的 site 也在启动时读取,改后请重启 dev
siteConfig.avatar / logo否是favicon 是硬编码 /logo.webp,换路径要同步 BaseLayout.astro
siteConfig.defaultLang是是检查 src/i18n/*.json 是否有对应词条
siteConfig.defaultTheme否是—
siteConfig.postsPerPage否是分页路由数量变化
siteConfig.nav否是新增自定义页面需同步 SiteHeader.astro 的 NAV_DEFS 与 i18n nav.* 词条;缺失 / 非字符串数组时回退为仅「首页」并输出英文 console.warn(lib/siteConfigGuard.ts)
siteConfig.statsScript / commentScript否是对应插件文件需存在并完成配置
siteConfig.autoUpdatePostUpdated是是会改写 md 源文件
siteConfig.musicPlayer否是自动扫描依赖 public/music/ 内容
siteConfig.pet否是仅决定是否输出宠物 DOM(含名片上的唤回按钮);整个字段缺失不会报错(可选链读取),但会输出英文 console.warn
astro.config.mjs 任意项是是—
content.config.ts schema是是已有文章可能校验失败,注意 .astro/ 类型缓存
main.css 变量否(HMR)是—
pagefind.yml—是—