个人博客站点 - tianheg.co
blog/
├── assets/ # 构建时处理的资源
│ ├── css/ # Tailwind CSS 入口(`main.css`)+ 独立样式(`table.css`)
│ └── ts/ # TypeScript 组件(`main.ts`, `graph.ts`)
├── content/ # 网站内容
│ ├── posts/ # 博客文章(长文、随笔、年度总结)
│ ├── til/ # Today I Learned 笔记(知识点、操作步骤)
│ │ ├── software/ # 软件/工具/编程类(flat files, header-based grouping)
│ │ ├── life/ # 生活经验与技巧
│ │ ├── health/ # 健康与医学
│ │ ├── learning/ # 学习方法与思维模型
│ │ ├── career/ # 职业发展与思考
│ │ ├── hardware/ # 硬件设计与工程
│ │ ├── homelab/ # 家庭实验室
│ │ ├── backup/ # 备份方案与策略
│ │ ├── writing/ # 写作
│ │ ├── music/ # 音乐
│ │ ├── media/ # 媒体与内容
│ │ ├── courses/ # 课程笔记
│ │ ├── science/ # 科学
│ │ └── history/ # 历史
│ └── *.org # 独立页面(about, now, projects 等)
├── data/ # 构建时生成的数据
│ └── til-wordcounts.json # TIL 字数(Intl.Segmenter 分词)
├── layouts/ # Hugo 模板
│ ├── _default/ # 基础模板(section.json.json)
│ ├── _partials/ # 可复用组件(head, components)
│ ├── posts/ # 文章专用模板(single.html)
│ ├── til/ # TIL 专用模板(baseof, list, single)
│ ├── footprints/ # 足迹地图(single.html)
│ ├── important-now/ # 当前重点(single.html)
│ ├── graph/ # 知识图谱(list.json.json)
│ ├── section/ # 分类页(graph.html)
│ ├── baseof.html # 所有页面基础框架
│ ├── home.html # 首页
│ ├── single.html # 独立单页(About, Now 等)
│ ├── section.html # 分类列表页
│ ├── taxonomy.html # 标签聚合
│ ├── term.html # 单标签详情
│ └── 404.html # 404 页面
├── scripts/ # 构建和工具脚本
│ ├── build.sh # CI 构建脚本(Cloudflare Workers)
│ ├── worker.js # Cloudflare Worker(静态托管 + 语义搜索 API)
│ ├── generate-embeddings.mjs # 语义搜索嵌入生成
│ └── count-words.mjs # CJK 准确 TIL 字数统计
├── static/ # 静态文件(直接复制到 public/)
│ ├── images/ # 图片资源
│ ├── fonts/ # 字体文件
│ ├── projects/ # 项目展示相关文件
│ └── pagefind-semantic/ # 语义搜索原始文本数据
├── hugo.yaml # Hugo 配置
├── package.json # npm 依赖和脚本
├── wrangler.jsonc # Cloudflare Workers 配置
└── AGENTS.md # AI agent 上下文(symlink → README)
| 类别 | 技术 | 说明 |
|---|---|---|
| 静态生成 | Hugo | 标准版,支持 PostCSS/Tailwind |
| 样式 | Tailwind CSS v4 | 通过 @tailwindcss/cli 构建 |
| 搜索 | Pagefind | 静态搜索索引,基于构建后的 public/ |
| 图谱可视化 | vis-network | 分类页 JSON 数据驱动 |
| 部署 | Cloudflare Workers | 参考 hosting-cloudflare-worker |
| 依赖 | 版本 | 说明 |
|---|---|---|
| Hugo | ≥ v0.140 | 标准版即可,Tailwind v4 需要 |
| Node.js | ≥ 18 | npm 管理依赖(npm install) |
首次克隆后执行:
npm install| 目录 | 格式 | 原因 |
|---|---|---|
content/ 及根目录独立页面 |
Org Mode (.org) |
Hugo 原生渲染,个人偏好 |
content/til/ |
Org Mode (.org) |
笔记类内容,按分类文件夹组织,子分类用 #+HEADER 标记 |
| 目录 | 推荐格式 | 示例 |
|---|---|---|
posts/ |
{主题词}.org |
2025.org, a-dream.org, about-good-posts.org |
til/软件/ |
{前缀}-{描述}.org |
git-rebase.org, css-flexbox.org |
til/其他分类/ |
{描述}.org |
sleep.org, iptables.org |
扁平化结构下,子分类用 #+HEADER 标记,不建立子目录:
#+TITLE: Git merge 与 rebase
#+HEADER: Git
分类页按 header 分组展示,右侧边栏可折叠筛选。支持多 header(空格分隔)。
通用约束:
- ❌ 不能有大写字母
- ❌ 不能有空格
- ❌ 不能有中文标点
- ❌ 避免无意义编号(
001.org,note1.org)
#+TITLE: 文章标题
#+DATE: <2026-01-01 Thu 00:00>
#+TAGS[]: 标签1 标签2
独立页面(如 about.org)通常只需要 #+TITLE。
| 类型 | 适合内容 | 示例 |
|---|---|---|
| Posts | 长文、年度总结、随笔、书评、需要深度思考的内容 | 年终总结、音乐剧观后感、技术长文 |
| TIL | 技术知识点、操作步骤、命令备忘、可快速检索的笔记 | Git 命令、CSS 技巧、配置方法 |
tags是唯一的 taxonomy- 在
posts/中使用#+TAGS[]:添加 til/不推荐使用标签,文件夹分类已足够
TIL 的信息源链接统一放在文件末尾:
- 单一来源 →
来源: [[URL][描述文字]] - 多个来源 →
* 参考小节,Org link 列表
// 单一来源
来源: [[https://en.wikipedia.org/wiki/Asperger_syndrome][Wikipedia: Asperger syndrome]]
// 多个来源
* 参考
- [[https://en.wikipedia.org/wiki/Information_retrieval][Wikipedia: Information retrieval]]
- [[https://scholar.google.com/intl/en/scholar/help.html][Google Scholar Search Tips]]
注意:
- 内联引用(正文中随文出现的链接)不受此约束
- 推荐阅读/延伸资源不属于"信息源",不用加到
* 参考,用** 推荐资源或其他合适的小节标题
| 模板 | 用途 |
|---|---|
baseof.html |
所有页面基础框架(HTML 骨架) |
home.html |
首页 |
single.html |
独立单页(About, Now, Projects 等) |
posts/single.html |
博客文章详情页 |
til/single.html |
TIL 笔记详情页 |
section.html |
分类列表页(Posts, TIL 索引等) |
_default/section.json.json |
默认分类 JSON 输出 |
graph/list.json.json |
知识图谱 JSON 数据 |
_shortcodes/ |
自定义 Hugo 短代码 |
# 开发服务器(含热重载)
npm run dev
# 构建站点(自动运行字数统计 → Hugo)
npm run build
# 构建 + 生成搜索索引(完整发布流程)
npm run all
# 仅生成搜索索引(需先构建)
npm run pagefind
# 生成语义搜索索引(调 Cloudflare Workers AI,需先 build;改动内容后发布前必跑)
npm run embed
# 单独运行 TIL 字数统计(CJK 准确分词)
npm run words- 根据内容类型选择
content/posts/或content/til/下的正确分类 - 按命名规范创建
.org文件,填写 frontmatter - 运行
npm run dev本地预览 - 内容完成后运行
npm run all && npm run embed构建并更新搜索索引(关键词 + 语义) - 提交变更
| 资源类型 | 存放位置 | 说明 |
|---|---|---|
| 图片(内容引用) | static/images/ |
直接复制到 public/images/ |
| 图片(构建处理) | assets/ |
Hugo 管道处理(当前项目较少使用) |
| 字体 | static/fonts/ |
直接复制 |
| 项目展示文件 | static/projects/ |
直接复制 |
| CSS | assets/css/ |
Tailwind 入口文件 |
| JS/TS | assets/ts/ |
TypeScript 组件 |
注意: public/ 是 Hugo 构建输出目录,属于生成产物,请勿手动修改其中的文件。
| 页面类型 | 输出 | 说明 |
|---|---|---|
| 首页 | HTML + SectionsRSS | SectionsRSS 是按分类(section)分组的 RSS |
| 单页 | HTML | 文章、TIL、独立页面 |
| 分类页 | HTML + JSON | JSON 用于知识图谱可视化(vis-network) |
| 标签页 | HTML | 标签聚合列表 |
| 标签详情 | HTML | 单个标签下的内容列表 |
- 关键词搜索由 Pagefind 提供
- 索引基于
public/构建后的 HTML 生成 - 必须先
npm run build,再npm run pagefind pagefind_extended命令还会生成搜索 playground(本地调试搜索)
- 语义搜索(
/search的 AI tab)由 构建时预生成的 embeddings 驱动 npm run embed调 Cloudflare Workers AI(BGE-M3)生成全部页面向量 →static/pagefind-semantic/embeddings.bin(L2 归一化,提交 git)- Worker 运行时只嵌入 query + dot product,无冷启动、无 KV 缓存
⚠️ 改内容后必须重新npm run embed并提交,否则语义搜索结果缺新内容
- Graph 页面(
/graph)使用 vis-network 可视化内容关联 - 数据来源于分类页的 JSON 输出(
graph-datapartial →graph/index.json) - Org-mode 内链(
[[path][title]])作为节点关联的依据 - vis-network 仅在含
<content-network-graph>的页面加载(独立graph.ts入口)
- 平台: Cloudflare Workers
- 参考实现: hosting-cloudflare-worker
- 构建命令:
npm run all(Hugo 构建 + Pagefind 索引) - 输出目录:
public/ - 部署方式: 将
public/内容上传至 Cloudflare Workers
实际部署脚本和配置见项目根目录的
wrangler.jsonc和scripts/build.sh。