基于 Typora 的笔记站点构建系统

这是一个“配置驱动”的轻量静态站点生成器,面向 Typora 导出的 HTML 笔记:

项目的设计目标是“尽量不侵入笔记内容”:不搬运图片、不改写文章内部链接与图片引用,仅在文章 HTML 中插入少量资源引用(CSS/JS)和一个 meta 元素作为“返回主页”的锚点。

适用场景

快速开始

0) 环境要求

1) 准备你的 Typora 导出目录

保持 Typora 默认导出结构即可(同级资源目录):

本仓库示例是把“站点输出”和“文章目录”都放在 site/ 下,你也可以把文章放到任意目录,只要配置 scan 指向它即可。

2) 最小配置(site.config.json)

在仓库根目录创建/修改 site.config.json,最小可用版本如下:

说明:

3) 一次构建(生成首页 + 文章页注入)

会产生/更新:

4) 本地预览

推荐用 HTTP 方式预览(避免 file:// 下相对路径、脚本加载等差异):

方式 A:以仓库根目录作为站点根

浏览器打开:

方式 B:直接以 site/ 作为站点根(更接近部署到子目录时的体验)

浏览器打开:

项目原理(从概念到机制)

1) 两类输出:首页与文章页增强

2) 标签模型:主标签 / 副标签(Primary / Secondary)

这里的“主 / 副标签”是一个分工明确的模型,目的是:既能用目录做分组(稳定、低维护),也能用侧车做主题标注(不侵入正文)。

一个直观的例子:

最终用于“标签筛选与计数”的是 effective_tags

3) 侧车标签文件约定(*.tags.txt)

对每一篇文章 xxx.html,可以创建同名标签侧车文件(两种命名都支持):

内容写法:

示例:

4) 增量缓存(为什么它快、也为什么它稳)

构建时会读写 cache.path(JSON 文件),缓存每篇文章的关键信息:

因此:

一个额外的小细节:注入时会尽量保留文章文件的原始 mtime(避免“注入导致全站文件时间被改写”,影响你对真实更新时间的判断)。

5) 首页的筛选机制(URL Hash + data-tags)

首页每一条文章项都会带上 data-tags='[...]'(JSON 数组),前端通过 URL Hash 做筛选:

为了避免筛选后列表末尾出现多余分隔线,脚本会动态为“每个分组内最后一个可见项”打上 .last-visible 类来修正样式。

构建流程(build_site.py 做了什么)

python build_site.py --config site.config.json 的逻辑可以概括为:

  1. 读取配置(site_config.py):路径按配置文件所在目录解析为绝对路径

  2. 准备 UI 资源(site_ui_assets.py):把 assets/ui/float-panel.css/js 复制到 ui.assets_dir

  3. 扫描文章(非递归):只扫描每个目录的第一层 *.html(特殊情况:当 scan_dir==output_dir 会多扫一层子目录)

  4. 为每篇文章生成元数据:

    • 标题:优先取 HTML 中的 h1,其次 h2,再其次 <title>,最后回退为文件名

    • 标签:主标签来自目录名;副标签来自 *.tags.txt

    • 归一化/别名/隐藏:由 tags.normalizetags.aliasestags.hide_tags 控制

  5. 增量注入(并发):对“需要注入”的文章页插入/更新浮动面板所需的标签

  6. 渲染首页:

    • 顶部区:最近更新(home.recent_count)、推荐阅读(home.recommended

    • 导航区:所有标签及文章数量(按数量降序)

    • 分组区:按主标签分组显示文章列表

  7. 写入缓存与首页输出:

    • 如果首页内容无变化,会提示“主页无变化”并避免重复写文件

文章页注入机制(inject_ui.py 做了什么)

python inject_ui.py <文章.html> --config site.config.json 会在文章 HTML 中:

注入的路径全部使用“相对文章所在目录”的相对路径计算,因此:

配置项详解(site.config.json)

所有路径字段都支持绝对路径与相对路径;相对路径会以配置文件目录为基准解析。 (本文提到的“相对路径”,如果是在说配置项的取值,默认都是相对于 site.config.json 所在目录。)

site

scan(必填)

home

exclude_names / exclude_dirs

cache

ui

tags(可选)

用于“标签归一化/别名/隐藏”:

常见问题

1) 为什么我双击打开 HTML 看不到浮动面板?

更推荐用 python -m http.server 预览。file:// 环境下,浏览器对脚本/资源加载、相对路径解析更敏感,容易出现“资源加载失败但不明显”的情况。

2) 为什么“更新于 {time}”没变?

构建时间来自缓存:当“文章列表签名 + 配置文件内容”都未变化时,会沿用上一次构建时间。想强制更新时间变化,可以:

3) 我希望输出目录更干净,能把生成的 index 放进子目录吗?

可以,直接把 site.output 设为 site/index.html(本仓库示例就是这样)。同时建议把 cache.pathui.assets_dir 一并放到同一个输出根下(例如 site/.cachesite/assets/ui),便于整体搬迁与部署。

你可能会改的地方

🏠 我的博客