Skip to content

Latest commit

 

History

History
39 lines (20 loc) · 7.23 KB

architecture.md

File metadata and controls

39 lines (20 loc) · 7.23 KB

架构

单仓库、单 TanStack Start 应用、单 Cloudflare Worker。TanStack Router 提供类型化导航,TanStack Query 管理动态状态。CSS Modules 和 CSS 变量提供视觉系统。公开页面预渲染,动态会话和评论在 hydration 后读取。

主导航在桌面与移动端统一提供博客和项目入口,点击站点品牌返回首页。导航不显示当前页面的选中高亮或底部圆点。关于页面已移除,/about 返回 404,不再进入预渲染清单或 sitemap;about 仍为保留路径名,避免项目占用。

共享 Shell 顶栏使用固定定位和主题背景,始终位于窗口顶部。全局 --header-height 统一桌面 60px、手机 56px 的顶栏高度、正文顶部留白与根滚动容器的锚点偏移;文章和项目文档的粘性目录在顶栏下方停靠,章节侧栏的可滚动高度同时扣除顶栏高度。跳到正文链接保留更高层级,手机导航与账号浮层继续依附顶栏。手机博客网格允许列缩到可用正文宽度,代码块在自身容器内横向滚动,避免撑宽页面和顶栏。

内容从 content/ 经构建脚本校验和编译 MDX,生成模块清单、HTML 搜索输入、RSS、sitemap 和重定向清单。生产生成阶段排除草稿;只有显式本地预览才包含草稿。Pagefind 索引由公开内容生成并作为静态资源部署。

客户端通过 Start server functions 调用服务端,src/server/ 封装会话、D1、审核和防刷。数据库访问不进入客户端包。公共 HTML 无会话信息,动态接口和后台使用 private/no-store。Worker 入口处理 canonical 域名、重定向、安全响应头和健康检查。

内容 ID 默认是稳定主键,slug 只决定 URL;fn 更名同步 ID 的用户确认例外见 内容规范。历史 URL 在 frontmatter aliases 中显式保留。正文不存入 D1。D1 使用 Drizzle schema 与可审计 SQL 迁移。评论和审核写入通过 D1 batch 保持原子性。

本地 Vite Cloudflare 插件在 workerd 中运行后端;Bun 只用于工具链。预发布和生产资源隔离。无密钥时正文仍可阅读,登录和评论显示可理解的配置状态。

免费套餐采用 Assets 优先路由,公开页面和搜索资源不经过 Worker。只有认证、server functions、后台和健康检查优先执行 Worker。静态安全响应头与预发布 noindex 放在 public/_headers;历史路径由内容生成 _redirects,www 跳转和 HTTPS 由域名规则执行。动态请求额度耗尽不应阻断已发布正文。

后台预渲染不含用户信息的登录界面,入口仍经过 Worker 添加 private/no-store;管理数据仅在客户端会话确认后通过管理员接口加载,避免每次打开后台都执行 React 服务端渲染。

项目采用顶层 /$project 嵌套路由,父路由校验项目并提供共享文档布局;/$project/ 展示项目介绍作为 Home,/$project/docs/$ 匹配多级章节 slug。Home 与章节共用侧栏和本页目录,Home 的下一篇指向首篇章节,首篇章节的上一篇返回 Home。文档必须在当前项目内查找;未知项目、缺失章节返回 404,无章节项目仍可阅读 Home。全站统一使用 /projects 作为项目入口;独立 /docs 集合页及 /<project>/docs 概览地址均返回 404,不提供迁移跳转。项目工具栏已移除,搜索继续从全站顶栏进入。侧栏首项和返回项目首页的相邻导航均显示项目名称;项目首页与章节正文直接从标题开始,不显示面包屑或标题上方的 Home/分组标签。

每个项目的介绍、文档和导航集中在 content/projects/<目录名>/。构建以项目稳定 ID 注入文档关系,按导航配置生成分组和顺序,同时输出仅含公开内容的统一清单。页面元信息与 MDX 正文入口分离,集合页无需导入所有正文。清单中的 publicPaths 是预渲染和 sitemap 的共同来源;每个项目只生成一个 Home 路径,不额外生成文档概览路径。路由结构与配置决策见 ADR 0002。

项目 Home 通过 start.doc 稳定 ID 查找已公开的安装文档;项目卡片整体作为单个链接进入 Home,名称、描述和留白区域均可点击,右上角“文档”作为视觉提示。整卡共用悬停与键盘焦点反馈,保留原生链接的键盘导航和新标签页打开行为。开始入口的跨项目、缺失与草稿引用由构建阻断,未新增下载服务或运行时外部请求。FIA 与 fn 沿用同一套路由、预渲染和搜索筛选。

首页仍由 Assets 提供预渲染 HTML,时间区域输出固定占位,客户端 hydration 首次渲染与之保持一致。src/lib/use-current-time.ts 在挂载后按秒对齐重新读取设备时间,后台标签页暂停定时器,恢复可见时立即校准,离开页面时移除监听及计时器。不会把构建时间固化成访客看到的当前时间。

src/lib/time.ts 负责本地公历和进度计算;日历日序采用 UTC 归一化后的年月日计算,避免夏令时产生偏移;年/月/周/日进度以实际本地时间边界的毫秒差为准。小时与分钟进度表示钟面位置,夏令时重复小时会重复对应进度。首页仅按稳定 ID year 选取今年的进度用于渲染,预渲染占位与客户端展示一致;所有屏宽均显示单条全宽进度。src/lib/chinese-calendar.ts 使用锁定的 lunar-typescript 计算北京时间中国历法,独立于访客时区。缓存由挂载的首页持有,按北京时间日期、节气交接边界失效,系统时间回拨也会重新计算;时辰与倒计时由当前瞬间派生。历法转换失败当天显示不可用,公历时钟继续工作,次日重新尝试。无新增 Worker 请求、数据库或全局服务端状态。

时间首页的总标题和四个区域标题仅供辅助技术读取,保持 h1/h2 与区域命名;视觉上不显示这些标题、编号、说明栏或分区横线。时间数据、时区计算和缓存不受此布局调整影响。

共享 Shell 页脚只保留版权、站点链接与指向 /rss.xml 的订阅按钮,所有公开页面使用同一底栏;首页的时间来源提示已移除,无数据或订阅接口变化。

博客与项目集合页移除顶部介绍区的编号、宣传标题、说明和分割线,正文以 32px 顶部留白直接展示标签筛选 / 文章列表或项目分类。项目按 category 分组,缺少类别时归入“个人项目”,类别及组内顺序沿用内容清单;卡片只显示图标、名称、描述和文档入口,桌面两列、760px 及以下单列。页面保留仅供辅助技术读取的 h1(“博客” / “项目”)和原有 SEO。

博客与项目集合页通过 codeSplitGroupings: [] 随基础路由代码加载,共用的卡片样式也在首屏加载,避免首次点击再等待列表页 JS/CSS。两页只消费已生成的元信息,不请求 Worker 或 D1;文章、项目详情、文档正文和首页历法仍按路由拆分。不要为消除列表导航等待而预加载全部正文或关闭全站代码拆分。

GitHub 项目资源归属 semicoder-dev;页脚源码入口和隐私页问题反馈使用组织仓库。个人身份展示与认证数字 ID 不因项目迁移改变。