obsidian的双链构造-vite插件
在之前的个人博客设计中,怎么处理 md 的 frontmatter 的格式,现在想到一个好的办法,使用 vite 插件,通过设置 rootDir 目录,模仿 obsidian 的 metadataCache 来构造双链和按需导入相对路径的图片,原来的插件可以去掉,要明确责任, obsidian-cache 只负责全局视野
需要维护一个双向图
核心数据结构 (Containers)
快速扫描阶段 建议在 JS/TS 中使用以下四个容器来实现 $O(1)$ 级别的快速检索:
metadataCache(Map<string, FileMetadata>):- Key: 文件的相对全路径 (如
vault/work/project-a.md)。这是全库唯一的标识符。 - Value: 包含 Frontmatter、标题列表、最后修改时间、Slug 等。 用自己的 util 工具解析。特别是 outlinks,从 [[]] 中提取出来
- 后续分类,标签,的过滤和总数从这里遍历
- 先只解析 md 文件,其他文件格式只有 mtime 和 size,hash 也空字符串,
- Key: 文件的相对全路径 (如
filenameToPath(Map<string, string[]>):- Key: 文件名(含后缀,如
project-a.md,123.jpg)。 - Value: 一个路径数组。支持重名文件消歧义。
- 后续查询的时候,如果查询的文件名没有后缀,自动添加 .md
- Key: 文件名(含后缀,如
aliasesToPath(Map<string, string[]>):- Key: 别名文字(如
项目X)。 - Value: 路径数组。一个别名可能指向多个文件(虽然不推荐,但系统需兼容)。
- Key: 别名文字(如
slugToPath(Map<string, string>):- Key: 最终生成的 URL Slug。
- Value: 对应的文件路径。用于 SvelteKit 路由根据 URL 找文件。
快速扫描结束,需要管理双链,实现一个邻接表
"A.md": { "B.md": [ { "position": { "line": 5 }, "text": "别名1" } ], "C.md": [ { "position": { "line": 10 }, "text": "别名2" }, { "position": { "line": 45 }, "text": "C" } ] }
![]()
删除 src/lib/obsidian-cache 我重新建一个 vite 插件,目的是在指定目录下,获取目录内的 md 文件的双链关系
插件初始化 ,启动阶段
首先加载之前的缓存 json,也可以为空
扫描所有文件的,包括图片和其他附件,构建缓存条目,方便双链去定位和链接 ,这个可以异步进行,先是把容器目录的相对路径作为 key,系统文件的修改时间 mtime 和 size,计算 hash(md 需要,其他条目的 hash为空字符串),这一步先不解析 md里面的内容
对比之前的缓存 json,对比相同 key 的 mtime 和 size ,如果都相同, 就用之前的解析结果,如果不同,再对比 hash,hash 相同也行。Hash 不同,则需要进行 md 文件解析
解析文件除了 frontmatter 需要用 util 解析,还需要关注 [[]] 的链接
/** Raw link from Phase 1 — link is unresolved basename, type not yet set */
Export interface RawLink {
link: string; // raw basename (e.g. 'My Note' or 'image.Png')
Original: string; // raw markdown text
DisplayText?: string;
Embed: boolean; // true = ! Prefix
}
放在 metadata 中,字段名是 outlinks 数据结构为 RawLink[]
扫描完成,下一步 进行双链构建 用一个单独的类 这个阶段,所有的 md 文件都有 metadata 信息了,包括 slug,oulinks,
提取所有 slug 名,构建一个 slugToPath 的 map,方便构建的时候获取 slug 的映射和总数,这个和双链无关,但是其他地方需要用到
为了构建双链,我需要 filenameToPath 和 aliasesToPath 两个 map。对外暴露出查找方法,让 rawLink 中的 link (raw basename ) 能找到文件 唯一的 key。这个查找方法需要判断查找参数是否包含 .md,不过不包含,需要补全 .md,还要去 aliases 中查询,如果有完整的后缀名,就不去 aliases 中查询
这三个 map 在遍历 metadata 的时候一起生成
这时候,再进行第二次遍历,使用 metadata 的 outlinks 里的 link 去查找是否存在文件, 用 filenameToPath 或者 aliasesToPath,找到了在 metadata 中加入一个新的字段 resolvedLinks,link(raw basename)和 对应 pathKey 加入进去
obsidian的双链构造-vite插件
转载或引用本文时请遵守许可协议,注明出处、不得用于商业用途!