hugo obsidian 结合实践

背景

我的笔记软件是 Obsidian,博客发布工具是 Hugo,在不做任何配置的情况下,发布一篇文章是比较麻烦的。

流程一般是:在 Obsidian 中写完文章后,将修改的文章覆盖拷贝到 Hugo content/posts/ 下,再发布。这样做有几个问题:

  • 需要多执行一次 cp 命令
  • 需要记住修改了哪个文件,有心智负担。或者可以将整个目录全量拷贝,但如果文章数较多,这么做显然不够优雅
  • 无法在用 Obsidian 编辑文章时实时预览 Hugo 页面效果

因此,最好能直接使用 content/posts/ 目录作为 Obsidian vault。经过尝试,发现这种方式是可行的,不过需要做一些配置。

忽略 Obsidian 文件

Hugo 项目在创建时就使用了 git 管理,所以首先要配置的是 .gitignore,Obsidian 的配置文件是没有必要上传到 GitHub 的。

bash 复制代码
# .gitignore
.obsidian/
.trash/

其次要做的是让 Hugo 在渲染时忽略 Obsidian 配置文件,Hugo 提供了 2 种忽略文件的方法:

官方更推荐 mounts 的方式,我这里也采用 mounts 方式,配置如下:

toml 复制代码
# 配合 Obsidian,需要对目录重新映射
[module]
# 渲染时忽略 obsidian 文件
# 经测试,点开头的目录不会被打包,不用添加到这里了
# glob 与正则写法不同。若要忽略多个目录,需要写成 {folder1,folder2},注意逗号后不能有空格
[[module.mounts]]
  excludeFiles = 'posts/{template}/*'
  source = 'content'
  target = 'content'

使用图片资源

更新:以下方法还是比较复杂,不推荐使用了,更优的方法可以参考我的另一篇文章 用 Hugo Render Hooks 简化 Markdown 中链接、图片的引用


这部分折腾了很久,原因是 Hugo 不兼容 Obsidian 生成的链接格式。Obsidian 使用相对路径或绝对路径引用资源,在 Hugo 中都无法展示图片。于是搜索了下怎么解决。

首先,DoIt 主题介绍了 3 种使用资源的方式,但这几种方式需要更改目录结构,或将资源放到 Obsidian vault 以外的地方,都不合适。

接着去了解了 Hugo 建议的使用资源方式:

  1. 将资源放在靠近 md 的位置
    需要将目录结构改造成 Page BundlesPage Resources 中的结构,md 文件命名为 index.md这里有个例子。这种方式破坏了结构,我肯定不能接受。
  2. 把资源都放到 static 目录下
    参考 Static Files
    (1) 可以通过配置 staticDir 使用多个目录,那就可以尝试把 content/posts/assets 作为 static files。
    (2) 另外,在搜索时发现有人通过 mount static 目录 的方式使用资源,可以尝试下。

由于官方更推荐用 mount,那就用这种方法试下。

配置 Obsidian:设置插入资源链接时使用绝对路径

配置 Hugo:

toml 复制代码
[module]
[[module.mounts]]
  # glob 与正则写法不同。若要忽略多个目录,需要写成 {folder1,folder2},注意逗号后不能有空格
  excludeFiles = 'posts/{template,assets}/*'
  source = 'content'
  target = 'content'
[[module.mounts]]
  source = 'content/posts/assets'
  target = 'static/assets'

这时发现 Hugo 还是不展示图片,原因是 Obsidian 插入图片的链接格式为 assets/xxx.png,Hugo 不兼容该写法,必须要在最前面加上 /

注:为了让 Obsidian 自动给链接加上 /,可以使用 Linter 插件,配置 Custom Regex Replacement

改好后看起来 ok 了,但引入了个新问题:mount 后,原先的 static 目录被替换掉了,而 favicon 在原来的 static 目录下,mount 后就无法显示了。

查了下 mount 能否 merge,发现是可以的,配置如下:

toml 复制代码
[[module.mounts]]
  source = 'static'
  target = 'static'
[[module.mounts]]
  source = 'content/posts/assets'
  target = 'static/assets'

自动生成并更新 front matter

Hugo 在渲染文章时需要用到 front matter 中的信息,手动创建太麻烦了,最好能用模板自动创建。

下面借助 2 个 Obsidian 插件实现自动生成并更新 front matter:

  • Templater(插入 front matter)
  • Linter(更新 front matter)

首先介绍一下 Templater 的使用

Templater 插件

概念:

  • template:模板文件
  • command:<% xxx %> 的结构,类似表达式
  • function:就是 JS 的函数,分为 internal functions(预置函数,如 tp.date.now()) 和 user functions(自定义)
  • user functions:分为 Script User Functions 和 System Command User Functions

特殊的 command:

  • Dynamic Commands:以 <%+ 开头,github issue 中作者说以后会移除该功能,不推荐使用
  • Javascript Execution Command:以 <%* 开头,可执行 JS 代码
  • Whitespace Control:包括 <%__%><%--%>,用于去除模板留下的空行

配置:

  • 指定模板目录
  • 新建文件时使用模板:指定启用该功能的目录,并选择模板

一般在创建文件时使用模板就够了,如果想手动插入模板,也可以,在命令面板中输入 Templater: Open Insert Template Modal 即可。

当前我的模板是:

toml 复制代码
---
title: ""
date: <% tp.file.creation_date("YYYY-MM-DD[T]HH:mm:ss[+08:00]") %>
lastmod: 
categories: ["<% tp.file.folder(true).split('/')[0] %>"]
tags: [""]
summary: ""
---

接下来介绍下如何用 Linter 更新 front matter

Linter 插件

配置:

  • YAML Timestamp:用当前文件的最后修改日期更新 Date Modified Key。为了和 Hugo 的 key 一致,这里把 Date Modified Key 配置成 lastmod

注:

  • Date Modified 使用当前时间而非最后修改时间 不是 bug,而是正常的设计逻辑。因为如果当前文件中 Date Modified 的值不正确,使用最后修改时间更新 Date Modified,会导致文件的修改时间变化,这样每次 lint 都会更新,无限循环。使用当前时间即可解决这个问题,有一点误差问题不大。
  • 我的 front matter 使用了 TOML 格式(和 DoIt 主题保持一致),但该插件的一些配置是针对 YAML 的,所以不确定是否出问题。另外,Obsidian 的 front matter 只支持 YAML、JSON。

最后

最后,感谢以下文章引起了我折腾的兴趣,也为我提供了一些自动化的思路

相关推荐
肖哥弹架构9 小时前
Vue组件开发:从入门到架构师
前端·vue.js·程序员
我是陈泽1 天前
一行 Python 代码能实现什么丧心病狂的功能?圣诞树源代码
开发语言·python·程序员·编程·python教程·python学习·python教学
肖哥弹架构2 天前
Spring 全家桶使用教程
java·后端·程序员
IT杨秀才5 天前
自己动手写了一个协程池
后端·程序员·go
程序员麻辣烫7 天前
像AI一样思考
程序员
一颗苹果OMG9 天前
关于进游戏公司实习的第一周
前端·程序员
万少9 天前
你会了吗 HarmonyOS Next 项目级别的注释规范
前端·程序员·harmonyos
楽码10 天前
彻底理解时间?在编程中使用原子钟
后端·算法·程序员
江南一点雨10 天前
又一家培训机构即将倒闭!打工人讨薪无果,想报名的小伙伴擦亮眼睛~
java·程序员
用户861782773651810 天前
ELK 搭建 & 日志集成
java·后端·程序员