项目概览
这是一个名为 Clarity 的个人博客系统(v3.7.0-rc.0),基于 Nuxt 3 全栈框架构建,采用 SSG(静态站点生成) 方式部署。项目使用 pnpm 作为包管理器,TypeScript 编写,整体设计高度模块化、配置驱动。
整体架构分层
blog-v3/ ├── 配置层 → blog.config.ts / nuxt.config.ts / app.config.ts / content.config.ts ├── 应用层 (app/) → 页面、组件、状态管理、组合式函数、插件、样式 ├── 内容层 (content/) → Markdown 文章源文件 ├── 服务层 (server/) → API 路由、SSR 路由 ├── 模块层 (modules/) → 自定义 Nuxt 模块 ├── 构建层 → remark/rehype 插件、patches、scripts ├── 共享层 (shared/) → 前后端共用的工具函数 └── 静态资源 (public/) → 字体、XSL 样式等
配置层详解
1. blog.config.ts — 博客业务配置中心
作用:定义博客的所有业务级配置,是整个系统的"单一数据源"。
- 基础信息:站点标题、副标题、描述、作者信息、版权、favicon、语言、建站时间、URL
- 文章配置 (
article):分类定义(含图标和颜色)、文章类型(tech/story)、排序方式、permalink 策略、URL 前缀隐藏、SEO robots 规则 - 订阅源配置 (
feed):Atom feed 的文章数量限制、XSLT 样式开关 - 脚本注入 (
scripts):Umami 统计、Cloudflare Insights、Twikoo 评论 - 导出
myFeed:供 OPML 和友链页面使用的自身站点描述
2. nuxt.config.ts — 框架级配置
作用:Nuxt 框架的全局配置,整合所有模块和构建选项。
关键配置项:
- 模块注册:14 个 Nuxt 模块(content、icon、image、color-mode、seo、pinia 等)
- 内容处理:Markdown 渲染管线 — 自定义 remark 插件(音乐谱面、数学公式、阅读时间)+ rehype 插件(元数据插槽、KaTeX 数学渲染)
- 路由规则 (
routeRules):重定向映射、预渲染策略、Content-Type 头 - Vite 配置:SCSS 全局变量注入、依赖预构建优化
- Hooks:
content:file:afterParse钩子实现 permalink 重写和/posts前缀隐藏 - 运行时配置 (
runtimeConfig):构建时间、CI 环境、平台信息
3. app.config.ts — 客户端运行时配置
作用:定义前端运行时可访问的配置(通过 useAppConfig() 读取)。
- 继承
blog.config的所有配置 - 组件配置 (
component):Alert 样式、代码块折叠行数/缩进、摘要动画、Slide 展示、统计信息 - 页脚配置 (
footer):版权文本、图标导航、站点地图 - 头部配置 (
header):Logo、标题展示、副标题、emoji 尾缀 - 导航配置 (
nav):左侧栏导航菜单 - 分页配置 (
pagination):每页数量、默认排序、正序开关 - 主题配置 (
themes):浅色/深色/系统的图标和提示文本 - 友链配置 (
link):无订阅源提醒、分组内随机排序
4. content.config.ts — 内容集合定义
作用:使用 Zod 定义文章的 frontmatter 数据模式,确保内容数据的类型安全。
- 定义
ArticleSchema接口:title、description、date、updated、categories、tags、type、image、recommend、references、draft、permalink、readingTime - 集成
@nuxtjs/sitemap的 schema,自动生成 sitemap 的lastmod - 默认值:categories 默认为
blogConfig.defaultCategory,tags 默认空数组,type 默认首个类型
应用层详解 (app/)
1. 页面系统 (pages/)
| 页面 | 文件 | 功能 |
|---|---|---|
| 首页 | index.vue | 文章列表 + 精选 Slide + 分类筛选 + 排序 + 分页 |
| 文章详情 | [...slug].vue | 动态路由匹配所有文章路径,渲染文章内容 + TOC + 评论 |
| 友链 | link.vue | 友链展示页面 |
| 归档 | archive.vue | 按年份归档文章 |
| 预览 | preview.vue | 草稿/预览文章 |
首页数据流:
useAsyncData → getArticleIndexOptions() → 原始文章列表
→ useArticleSort() → 排序后列表 (支持 URL query 绑定)
→ useCategory() → 分类筛选后列表
→ usePagination() → 分页后列表
文章详情页数据流:
useAsyncData → queryCollection().path(route.path).first() → 文章数据
→ PostHeader / PostExcerpt / ContentRenderer / PostFooter / PostSurround / PostComment
→ layoutStore.setAside() → 动态设置右侧栏 widget
2. 组件体系 (components/)
组件按职责分为 6 个子目录:
blog/ — 博客布局骨架
BlogHeader.global.vue:全局注册的顶部导航栏(Logo + 导航 + 搜索 + 主题切换)BlogSidebar.vue:左侧栏(导航 + 搜索 + 主题切换)BlogAside.vue:右侧栏(动态 widget 容器)BlogFooter.vue:页脚(版权 + 站点地图)BlogPanel.vue:移动端面板控制器BlogWidget.vue:Widget 卡片包装器ThemeToggle.vue:主题切换按钮Mask.vue:遮罩层SkipToContent.vue:无障碍跳转链接
content/ — Markdown 内容增强组件(约 27 个)
- 排版类:
ProseA、ProseCode、ProsePre、ProseTable— 自定义 Markdown 默认渲染 - 交互类:
Alert、Badge、Copy、Folding、Tab、Tip、Blur、Secret - 媒体类:
Pic、VideoEmbed、MusicScore(abcjs 乐谱渲染) - 卡片类:
LinkCard、LinkBanner、CardList、FeedCard、FeedGroup - 特殊类:
Chat(对话气泡)、Poetry(诗歌排版)、Timeline、Quote、EmojiClock、MdTitle、Key(快捷键展示)
post/ — 文章相关组件
Article.vue:文章列表中的单篇文章卡片PostHeader/Footer:文章详情页头部/底部Excerpt.vue:文章摘要(带打字机动画)Slide.vue:精选文章轮播Archive.vue:归档视图Comment.vue:Twikoo 评论集成PostSurround.vue:上下篇导航OrderToggle.vue:排序/分类切换控件
partial/ — 通用 UI 组件(前缀 Z)
Button、Toggle、Slider、Dropdown、RadioGroup、Pagination、Expand、DlGroup、IconNavList、Secret、Error
popover/ — 弹出层组件
Search.vue/SearchItem.vue:全文搜索(基于 minisearch)Lightbox.vue:图片灯箱
widget/ — 侧边栏小部件
Toc.vue:目录导航(滚动高亮)BlogStats.vue:博客统计BlogTech.vue:技术栈展示BlogLog.vue:更新日志CommGroup.vue:交流群信息Empty.vue:空状态
util/ — 工具组件
Link.vue:智能链接(内部用 router、外部新窗口)Img.vue:图片优化组件Date.vue:日期格式化HydrateSafe.vue:安全水合包装器
3. 状态管理 (stores/)
layout.ts — 布局状态机
LayoutState = 'none' | 'sidebar' | 'aside' | 'search' | 'lightbox'
- 管理侧边栏/搜索/灯箱等面板的互斥展开状态
asideWidgets:控制右侧栏显示哪些 widgetavoidTargets:记录需要避让的 DOM 元素(分页组件吸顶时避让)- Escape 键关闭、路由切换自动关闭
search.ts — 搜索状态
- 与
layoutStore联动:搜索状态变化时自动开关搜索弹窗 word/debouncedWord:搜索关键词及防抖版本- 自动获取页面选中文本作为搜索词
4. 组合式函数 (composables/)
| 函数 | 功能 |
|---|---|
useArticle | 获取当前文章内容/TOC/metaSlots,生成文章查询参数 |
useCategory | 文章分类筛选,支持 URL query 绑定 |
useArticleSort | 文章排序(日期/更新日期),支持正序/倒序切换 |
usePagination | 通用分页逻辑,含分页指示器算法 |
useToc | TOC 滚动高亮,自动追踪当前阅读位置 |
useWidgets | Widget 渲染引擎,支持内置 widget 和 meta-aside 动态插槽 |
useCopy | 复制功能 |
useAvoid | 元素避让逻辑 |
5. 插件 (plugins/)
init.ts:应用初始化tippy.ts:Tooltip 提示库初始化easter-egg.ts:彩蛋功能
服务层详解 (server/)
API 路由
/api/stats — 博客统计 API
遍历所有文章,计算:
- 总文章数 + 总字数
- 年度文章数 + 年度字数
- 分类树形统计(支持多级分类)
- 标签去重聚合
/atom.xml — Atom 订阅源
使用 fast-xml-builder 生成标准 Atom XML:
- 查询最新 N 篇文章(按更新时间倒序)
- 每篇包含:标题、内容摘要、链接、分类、发布/更新时间
- 可选 XSLT 样式表(
atom.xsl)让浏览器中直接美化展示
/zhilu.opml — OPML 订阅列表
生成 OPML 格式的友链订阅源列表。
模块层 (modules/)
anti-mirror — 防镜像模块
- 维护一个黑名单域名列表(已知的镜像站点)
- 将检测逻辑编译为 IIFE(使用
oxc-minify压缩),注入到<head>的<script>中 - 客户端运行时检测当前域名是否在黑名单中,如果是则跳转到正确站点
构建工具层
Remark/Rehype 插件
- remark-music.ts:将 Markdown 中的音乐谱面代码块转换为 abcjs 可渲染的格式
- rehype-meta-slots.ts:从 Markdown frontmatter 中提取
aside插槽配置,允许文章自定义右侧栏内容
Patches
对依赖包的补丁修复:
@nuxt/image、@nuxtjs/mdc、@vue/shared、plain-shiki
Scripts
- new-blog.ts:交互式新建文章 CLI(选择分类、标签、类型,自动生成 frontmatter,打开 VS Code)
- init-project.ts:项目初始化脚本
- check-all-feeds.ts / get-feed.ts:友链订阅源检测工具
共享层 (shared/)
前后端共用的纯工具函数:
icon.ts:图标 URL 生成link.ts:链接处理str.ts:字符串工具time.ts:时间处理(toZonedTemporal时区转换,基于temporal-polyfill)
数据流与关系图
用户请求
│
├─ 首页 → useAsyncData → queryCollection → content/posts/**
│ → useArticleSort → useCategory → usePagination → PostArticle 组件
│
├─ 文章页 → queryCollection().path() → ContentRenderer → content/ 组件渲染
│ → layoutStore.setAside → BlogAside → widget 渲染
│
├─ /atom.xml → server route → queryCollection → XML 生成
├─ /api/stats → server API → queryCollection → 统计计算
├─ /zhilu.opml → server route → feeds.ts → OPML 生成
│
└─ 搜索 → layoutStore.toggle('search') → searchStore → minisearch 全文检索
配置流转:
blog.config.ts ──→ nuxt.config.ts (构建时)
──→ app.config.ts (运行时,通过 useAppConfig() 访问)
──→ content.config.ts (内容验证)
──→ server routes (API 数据生成)
──→ scripts (CLI 工具)
核心技术栈总结
| 类别 | 技术 |
|---|---|
| 框架 | Nuxt 3 (SSG) |
| UI | Vue 3 + 自定义组件库 |
| 状态 | Pinia |
| 内容 | @nuxt/content (Markdown + Zod schema) |
| 代码高亮 | Shiki + plain-shiki + @bikariya/shiki |
| 样式 | SCSS + CSS 变量(浅/深色主题) |
| 搜索 | minisearch (客户端全文搜索) |
| 评论 | Twikoo |
| 数学 | remark-math + rehype-katex |
| SEO | @nuxtjs/seo (sitemap + og + robots) |
| 图片 | @nuxt/image (avif/webp 自动转换) |
| 图标 | @nuxt/icon (Iconify) |
| 时间 | temporal-polyfill (Temporal API) |
| 构建 | Vite + pnpm workspace (catalog:) |
设计亮点
- 配置驱动:
blog.config.ts作为单一数据源,被构建时和运行时共享,避免配置分散 - 内容即数据:通过
@nuxt/content+ Zod schema,Markdown frontmatter 成为类型安全的数据源 - 动态右侧栏:文章可通过 frontmatter 的
aside字段自定义右侧栏 widget,rehype-meta-slots插件实现插槽注入 - 防镜像机制:自定义 Nuxt 模块,编译时注入压缩后的检测脚本
- URL 状态同步:排序、分类、分页、搜索等状态通过
useRouteQuery与 URL 双向绑定,支持分享和前进后退 - 渐进式水合:
HydrateSafe组件 +inlineStyles: false优化首屏性能
评论区
评论加载中...