site.config.ts
构建期确定的配置值,修改后必须重新构建
site.config.ts 内定义的值通常不会频繁修改,用作数据库站点信息的默认值,开发环境和构建过程会读取其中的全部配置。
site.config.ts 内每个字段都配有 JSDoc。使用类似 VSCode 的开发工具编辑时,将鼠标悬停在字段上即可查看注释。

搭建个人站点时,请将站点信息修改为自身信息,不要继续使用示例中的内容。
预定义变量
由于部分变量会在多个位置重复使用,因此文件开头定义了一组预定义变量,具体字段可直接引用或进一步处理。这些变量并非标准字段,而是为便于引用而手动定义的辅助变量。可按下例修改这些变量,后续派生字段会自动更新;也可以删除这些变量,直接设置标准变量中的各项值。
TypeScript// 原始字面量值(修改这些即可,下方派生字段自动更新)
const _name = "ImQi1";
const _desc = "做技术的分享者、生活的摄影师、时事的评论员。";
const _displayName = "做技术的分享者 · 生活的摄影师 · 时事的评论员";
const _nickname = "棋";
const _ownerName = "Qi1";
const _avatarPath = "/imgs/avatar.webp";
const _logoPath = "/imgs/imqi1.svg";
const _url = "https://imqi1.com";
const _cdnUrl = "https://cdn.imqi1.com";
const _host = new URL(_url).hostname;
// 站长对外链接:首页图标条与关于页按钮共用同一批字面量
const _email = "mailto:imqi1@qq.com";
const _website = "https://qi1.website";
const _github = "https://github.com/imqi1-github";配置按站点基础设置、构建、安全、SEO、页面、功能、日志七区组织,下一节会介绍。
各预定义变量在区内的引用位置如下:
| 变量名 | 引用位置 | 说明 |
|---|---|---|
_name | site.name、seo.pages 内多数页面的 description / keywords、pages.links.profile.siteName | 站点名 |
_desc | seo.description、seo.pages.home.description | 站点简介 |
_displayName | pages.homeCustomText、pages.links.profile.siteDescription | 首页展示的标语 |
_nickname | pages.links.profile.siteName | 昵称,拼在友链页的站点名里 |
_ownerName | site.ownerName | 站点所有者 |
_avatarPath | site.avatarPath | 头像的裸路径 |
_logoPath | seo.ogImage | 站点图标的裸路径 |
_url | site.url、pages.links.profile.siteUrl、_host | 站点地址 |
_cdnUrl | site.cdnUrl | CDN 根地址 |
_host | site.rootDomain、security.allowedRefererDomains | 由 _url 推出的域名 |
_email | pages.homeLinks[].link、pages.aboutLinks.email | 站长邮箱 |
_website | pages.homeLinks[].link、pages.aboutLinks.website | 站长个人网站 |
_github | pages.homeLinks[].link、pages.aboutLinks.github | 站长 Github |
说明:
- 通常只需修改原始变量值,派生字段和标准字段会自动更新;
- referer 校验与防镜像等防护在开发环境下均不生效,因此无需区分开发环境和生产环境的取值,直接设置为生产环境的值即可;
_url应设置为生产环境的站点地址。开发环境不会发生跳转,生产环境下如实际访问地址与该值不一致,则会发生跳转;- 静态资源写裸路径和以 https 开头的路径均可,前缀由 utils 内的
publicAsset自动处理。
标准变量
七个顶层对象依次是站点基础设置、构建、安全、SEO、页面、功能、日志:
站点基础设置
站点的名字、地址、CDN 根、头像与站长名:
TypeScriptdefineSiteConfig({
site: {
name: _name,
url: _url,
cdnUrl: _cdnUrl,
rootDomain: _host,
avatarPath: _avatarPath,
ownerName: _ownerName,
},
})| 字段 | 值 | 说明 |
|---|---|---|
name | _name = "ImQi1" | 站点名 |
url | _url = "https://imqi1.com" | 站点地址 |
cdnUrl | _cdnUrl = "https://cdn.imqi1.com" | CDN 根地址 |
rootDomain | _host = "imqi1.com" | 站点根域名 |
avatarPath | _avatarPath = "/imgs/avatar.webp" | 头像地址 |
ownerName | _ownerName = "Qi1" | 站点所有者 |
rootDomain 由 _url 推出,avatarPath 直接引用 _avatarPath,这两项会随预定义变量更新,无需单独修改。cdnUrl 填写 CDN 根地址,同时用于静态资源加速和 CSP 白名单,配置方法见 CDN 配置。
构建
构建期的压缩、体积分析与 Redis 连接:
TypeScriptdefineSiteConfig({
build: {
brotliCompression: true,
statsHtml: false,
redis: {
enabled: true,
host: "127.0.0.1",
port: 6379,
db: 0,
},
},
})| 字段 | 值 | 说明 |
|---|---|---|
brotliCompression | true | 构建时额外产出 .br 预压缩文件 |
statsHtml | false | 是否产出包体积分析页 stats.html |
redis.enabled | true | 生产构建是否启用 Redis |
redis.host | "127.0.0.1" | Redis 地址 |
redis.port | 6379 | Redis 端口 |
redis.db | 0 | Redis 库号 |
brotliCompression 开启后构建会额外产出 .br 文件,需要 Nginx 或 CDN 配合发送预压缩文件。statsHtml 平时保持关闭,只在排查包体积时打开,构建完会多出一个 stats.html。
redis 仅在生产构建中生效,开发环境始终不启用。它同时控制页面整页缓存和搜索缓存:保持默认开启时,页面缓存写入 Redis;关闭 enabled 后,两类缓存同时关闭,页面每次请求均实时渲染。本机部署保持默认配置即可,修改后需要重新构建。Docker 部署由构建参数覆盖,此处配置对 Docker 不生效,详见 Docker 部署。
安全
接口的 Referer 白名单与 CSP:
TypeScriptdefineSiteConfig({
security: {
allowedRefererDomains: [_host],
enableCsp: true,
},
})| 字段 | 值 | 说明 |
|---|---|---|
allowedRefererDomains | [_host] = ["imqi1.com"] | 允许访问 /api/* 的 Referer 白名单 |
enableCsp | true | 是否下发 CSP 响应头 |
allowedRefererDomains 是允许访问 /api/* 的 Referer 域名白名单,除了 _host 还有别的域名要调接口时在这里补上;/api/mini 与 /api/_nuxt_icon 豁免于这个白名单。
enableCsp 仅生产构建生效,本地预览打包产物时可以临时关掉,正式部署应保持开启。
SEO
默认文案、分享图与各页面的文案:
TypeScriptdefineSiteConfig({
seo: {
description: _desc,
keywords: "棋,ImQi1,棋的小站,生活,科技,编程,学习,摄影,时事",
ogImage: _logoPath,
ogLocale: "zh_CN",
twitterSite: "@imqi1_X",
pages: {
// ...
},
},
})| 字段 | 值 | 说明 |
|---|---|---|
description | _desc = "做技术的分享者、生活的摄影师、时事的评论员。" | 默认描述 |
keywords | "棋,ImQi1,棋的小站,生活,科技,编程,学习,摄影,时事" | 顶层关键词(暂无消费点) |
ogImage | _logoPath = "/imgs/imqi1.svg" | 分享图与页头 logo |
ogLocale | "zh_CN" | Open Graph 语言地区 |
twitterSite | "@imqi1_X" | twitter:site 账号 |
pages.* | home、about、links、messages、changelogs、sitemap、archiving、subscribes、search、map、agreement、notFound | 静态页面的逐页文案 |
pages.category | (name, desc) => string | 分类页,按名称与描述拼 |
pages.tag | (name) => string | 标签页,按名称拼 |
description 是默认描述,在数据库没有站点描述时用作兜底;顶层 keywords 目前没有消费点,各页的关键词都取 pages 内逐页的值。pages 内逐页的 description 与 keywords 才是最终文案,其中 category 与 tag 两个动态页面写成函数,接收名称和描述后拼出文案。
ogImage 同时用于 og:image 与 twitter:image,也是页头 logo,指向 _logoPath 的那张 SVG。twitterSite 是 twitter:site 的 @用户名。
页面
过渡动画、首页文案与三个页面的专属配置:
TypeScriptdefineSiteConfig({
pages: {
transition: {
fadeDuration: 150,
translateY: 14,
},
homeCustomText: `<p>${_displayName}</p>`,
homeLinks: [
// ...
{
name: "小程序",
icon: "ri:mini-program-fill",
qrcode: "/imgs/miniprogram.jpg",
},
],
aboutLinks: {
email: _email,
website: _website,
github: _github,
},
links: {
blogOrganizations: [
// ...
{ name: "十年之约", url: "https://www.foreverblog.cn/blog/5868.html", icon: "/imgs/foreverblog.png" },
],
profile: {
siteName: `${_name} / ${_nickname}`,
siteUrl: _url,
siteDescription: _displayName,
siteAvatar: "https://cn.cravatar.com/avatar/2841d29eeabab633ae116c7b2c97e3bf?s=512",
},
},
},
})| 字段 | 值 | 说明 |
|---|---|---|
transition.fadeDuration | 150 | 页面切换淡入时长(毫秒) |
transition.translateY | 14 | 页面切换位移幅度(像素) |
homeCustomText | <p>${_displayName}</p> = "<p>做技术的分享者 · 生活的摄影师 · 时事的评论员</p>" | 首页标语 |
homeLinks | 数组,7 项 | 首页图标条 |
aboutLinks | email / website / github | 关于页「交个朋友」的三个按钮 |
links.blogOrganizations | 数组,5 项 | 友链页展示的博客组织 |
links.profile | siteName 等 4 项 | 友链页展示的本站信息 |
transition 控制页面切换的动画时长与位移幅度。homeCustomText 是首页标语,也是数据库未初始化时的兜底值。
homeLinks 是首页那排图标,每项要么给 link 直接跳转,要么给 qrcode 悬浮弹二维码,给了 qrcode 的项就不再是链接;link 项可加 target: true 让它在新窗口打开;name 需要唯一,它同时是列表的 key 和弹层的 id。aboutLinks 对应关于页「交个朋友」的三个按钮。
links.blogOrganizations 是友链页展示的博客组织(关于页的十年之约入口也取自这里),icon 写 /imgs/ 开头的路径,图片放在 public/imgs/ 下;links.profile 是友链页展示的本站信息,其中 siteAvatar 需为完整地址,因为它没被 publicAsset 函数处理。
功能
小程序、二维码入口与高德地图的开关:
TypeScriptdefineSiteConfig({
features: {
miniApi: true,
miniComment: true,
miniFakeData: false,
mobileQr: true,
miniQr: true,
amap: {
proxy: true,
entry: true,
},
},
})| 字段 | 值 | 说明 |
|---|---|---|
miniApi | true | 是否注册小程序接口路由 |
miniComment | true | 是否启用小程序评论与留言 |
miniFakeData | false | 小程序审核模式开关 |
mobileQr | true | 文章页「本文可在【手机】上看」入口 |
miniQr | true | 文章页「本文可在【小程序】上看」入口 |
amap.proxy | true | 生产环境是否经服务端代理取高德密钥 |
amap.entry | true | 是否展示指向地图页的入口胶囊 |
miniApi 关闭后开发和生产都不再注册小程序接口路由;miniComment 是独立的小程序评论开关,关闭后小程序不展示评论区和留言入口,评论列表接口返回关闭状态,评论提交接口拒绝请求。主站后台「开启评论」只控制主站评论区,不影响这个配置。
miniFakeData 是构建期的小程序审核模式开关,开启后 /api/mini/* 只返回一篇固定占位文章,评论一并关闭,分类与归档只保留这一篇,友链、订阅、旅行、更新日志与音乐接口一律返回空,供微信提交审核时使用。审核通过后再改回 false 重新构建,配置改动需重新 build。小程序端另有自己的一份 mini/src/site.config.ts,改这里的配置对小程序无效。
mobileQr 与 miniQr 控制文章页「本文可在【手机】/【小程序】上看」两个入口,miniQr 生效还需在 .env 里配置微信小程序的 WECHAT_MINI_* 两项。
amap.proxy 决定生产环境是否经服务端代理取高德密钥,开发环境恒为直连。amap.entry 控制各处是否展示指向地图页的入口胶囊。
日志
文件日志的总开关、行格式、大小切分、保留与九类分类逐一开关:
TypeScriptdefineSiteConfig({
logs: {
file: true,
dir: "./logs",
lineFormat: "{ts} [{tag}] [{level}] {msg}{kv}",
maxFileSizeMb: 20,
retentionDays: 90,
categories: {
access: true,
audit: true,
auth: true,
external: true,
cache: true,
ratelimit: true,
cron: true,
monitor: true,
app: true,
},
},
})| 字段 | 值 | 说明 |
|---|---|---|
file | true | 文件日志总开关,false 时所有日志只打终端不落盘 |
dir | "./logs" | 日志根目录,.env 的 LOGS_DIR 优先于此值 |
lineFormat | "{ts} [{tag}] [{level}] {msg}{kv}" | 落盘行格式,占位符见 lib/site-config.ts 的字段注释 |
maxFileSizeMb | 20 | 单个日志文件大小上限(MB),超出切分为 {日期}.1.log,≤ 0 不切分 |
retentionDays | 90 | 每类日志保留天数,新的一天首次写入时清理过期文件,0 永久保留 |
categories.* | 九类各 true | 分类落盘开关,false 的类别只打终端不落盘 |
lineFormat 的占位符说明写在 lib/site-config.ts 的字段 JSDoc 里,编辑时悬停即可查看。日志的落点、分类含义与错误监控邮件见 日志系统。
类型定义
七个区的字段类型在 lib/site-config.ts 定义,由 defineSiteConfig 校验。