🚧 正在装修中 (v0.1):UES.ONE 还处于早期测试阶段,可能会遇到一些 Bug,请多包涵!🐛
UES.ONE:构建一个无 CDN、零闪烁的数据驱动型数字花园

UES.ONE:构建一个无 CDN、零闪烁的数据驱动型数字花园

December 5, 2025·Ahaxzh
Ahaxzh

在这个信息碎片化的时代,拥有一片属于自己的“数字花园”显得尤为珍贵。

终于,UES.ONE 上线了。它不仅仅是一个博客,更是我对 Web 技术、数据管理与用户体验的一次深度探索。

如果你厌倦了千篇一律的 CMS,或者对目前 Web 页面动辄几兆的 JS 依赖感到疲惫,那么这篇文章或许能给你一些不一样的灵感。在这里,我将带你从零开始,解构这个完全由 数据驱动零 CDN 依赖极致顺滑 的静态站点是如何构建的。

🌱 起步:为什么是 Hugo?

在技术选型之初,我考察了 WordPress、Hexo、Gatsby 等主流框架。最终,Hugo 凭借其令人发指的构建速度(毫秒级)和 Go 语言的强大生态赢得了我的青睐。

要在 macOS 上开始这一切,只需要一行简单的命令:

brew install hugo

为什么选择 Hextra 主题?

有了引擎,还需要一个漂亮的躯壳。我选择了 Hextra。它是一个基于 Next.js 风格文档主题改造而来的 Hugo 主题,不仅支持 Tailwind CSS,还完美融合了“文档”与“博客”两种布局。更重要的是,它的极简主义美学深得我心。

初始化项目并引入主题:

hugo mod init ues.one
hugo mod get github.com/imfing/hextra

就这样,骨架搭好了。但要让它拥有灵魂,还差得远。

🏗️ 核心架构:YAML 数据驱动 (Data-Driven Architecture)

传统的博客通常是一篇篇孤立的 Markdown 文章。但我是一个有“整理癖”的人。我希望我的书单、影单、音乐收藏能更有条理,更像是一个关系型数据库,而不是流水账。

因此,我制定了一个 “YAML First” 的数据策略。

data/ 目录下,我并没有写死 HTML,而是存储了高度结构化的数据:

  • books.yaml:阅读记录
  • movies.yaml:观影清单
  • music.yaml:音乐收藏
  • memos.yaml:碎碎念
  • quotes.yaml:精选名言

movies.yaml 为例,我是这样存储一部电影的:

- id: "m_001"
  title: 
    zh-cn: "黑客帝国"
    en: "The Matrix"
    ja: "マトリックス"
  year: 1999
  rating: 5
  poster: "matrix.web"
  comment:
    zh-cn: "你选蓝药丸还是红药丸?"
    en: "Blue pill or Red pill?"

有了这些数据,我编写了专门的 Hugo Shortcodes(如 moviewall.html),利用 Hugo 强大的模板引擎将 YAML 渲染成精美的海报墙。

这样做的好处是巨大的:未来如果我想从 Hugo 迁移到 Next.js 甚至移动端 App,我只需要带走这些 YAML 文件,而不需要去几百篇 Markdown 里像考古一样挖掘数据。

⚡ 性能哲学:反其道而行之的“零 CDN”

在 Web 开发过度依赖公共 CDN(如 jsDelivr, unpkg)的今天,我做了一个“反潮流”的决定:全站资源本地化

你在这个网站上看到的所有 JS 库(Swiper, Fancybox)和 CSS 样式,全部托管在本地的 assets/ 目录下。

为什么这么做?

  1. 隐私至上:没有 Google Fonts,没有第三方 Analytics 脚本。你的访问记录不会被任何大公司收集进行画像。
  2. 绝对可控:哪怕公共 CDN 宕机(这并不罕见),或者在弱网环境下,这个网站依然能完美运行。
  3. 构建优化:利用 Hugo Pipe,我在构建时对这些资源进行 Fingerprint(指纹)处理和 Minify(压缩),由 Cloudflare Pages 进行最终分发,速度丝毫不逊色于 CDN。

🎨 极致体验:告别 FOUC 与 智能预加载

1. 解决 FOUC (Flash of Unstyled Content)

静态网站在实现“暗黑模式”时,最容易遇到的问题就是 FOUC —— 页面加载瞬间,白色背景一闪而过,然后才变成黑色。

为了解决这个问题,我们采用了一种“透明优先,继承为主”的 CSS 策略。所有的卡片组件默认背景色设为 transparent,文字颜色设为 inherit。这意味着,无论浏览器首屏渲染时是亮色还是暗色,组件都会自然地融入背景,无需等待 JS 脚本执行完毕。

2. Memos 的“0 延迟”切换

Memos(碎碎念)模块中,我引入了 智能预加载 (Smart Preloading) 逻辑。

当你正在阅读当前的“卡片”时,浏览器已经在后台悄悄下载了“上一张”和“下一张”的图片资源。代码如下:

// 图片预加载优化:静默加载前一张和后一张的图片资源
var nextIdx = (index + 1) % memoData.length;
var prevIdx = (index - 1 + memoData.length) % memoData.length;
if (memoData[nextIdx].image) (new Image()).src = memoData[nextIdx].image;
if (memoData[prevIdx].image) (new Image()).src = memoData[prevIdx].image;

这种毫秒级的优化,造就了指尖滑动的极致顺滑感。

3. 一言 (Smart Quotes) 的跨语言同步

首页并没有使用公共的“一言” API,而是使用了我自建的 quotes.yaml 库。

更有趣的是,为了保证多语言切换时的体验一致性,我利用 sessionStorage 实现了状态同步:如果你在中文版首页看到了一句尼采的名言,当你切换到英文版时,你看到的依然是同一句名言的英文版,而不是随机跳到另一句。

这种细节的连贯性,是我对用户体验的执着。

🛠️ 今日重构:代码洁癖的胜利

就在今天,我对全站代码进行了一次大规模重构。

  • 配置标准化:将 hugo.yaml 从几百行杂乱的配置重组为 Core, Modules, Build, Multilingual 等七大板块。
  • 注释文档化:所有的 Shortcodes 和 Partials 文件,都补全了技术性中文注释。这不仅仅是为了给 AI 看,更是为了给未来的自己看。
  • 消灭 Bug:我们甚至为了修复一个 theme-toggle 的 HTML 属性值换行导致构建失败的问题,反复推敲了 Go Template 的语法边界。

结语

UES.ONE 是我的自留地,也是我的游乐场。

在这个过程中,我负责构思与审美,AI 负责代码实现与调试。Pair Programming with AI 已经成为我开发的新常态。我们为了一个 div 的高度争论过(比如那个 60vh 还是 70vh 的滚动条问题),也为解决了 z-index 的遮挡而庆祝过。

这是一个还在生长中的花园,代码在变,内容在变,但“用心创造”的初衷不变。

欢迎常来逛逛。

最后更新于