




















因为太忙,鸽了几个月,现在把这个系列收个尾。
继进阶篇介绍了 Trilium 的核心使用方法后,这篇文章将涉及 Trilium 中需要一定编程和折腾基础才会用到的功能,包括大家很关心的自建服务器同步和移动端。
最后,经过这几个月的深度使用,以及参考前两篇文章的反馈,我收集了一些常见的坑和小技巧,在此分享出来,希望能帮到遇到同样问题的人。
为了在多台机器间同步,并使用移动端,我们需要一个自己的 VPS 或类似的东西,并在上面搭建 Trilium 同步服务。此处仅分享我自己的配置,我用的是手动安装版本,另有打包版、docker 版等等,不在本篇介绍范围内,大家可以自行尝试。
另,这一节大量摘抄我在别处发布的 Trilium 配置笔记,所以如果看到遣词造句完全一样的文章不要惊慌,那也是我写的,自己抄自己。
参考资料:
环境:
首先安装 nodejs 10.x,版本必须在 10.5 之后。然后根据官方指南安装所有依赖:
sudo apt install libpng16-16 libpng-dev pkg-config autoconf libtool build-essential nasm libx11-dev libxkbfile-dev然后克隆最新稳定版源码并安装 npm 包:
git clone -b stable https://github.com/zadam/trilium.git
cd trilium
npm install这期间我遇到过一个报错:
g++: fatal error: Killed signal terminated program cc1plus
没有搜索到什么解决方法,某个回答说是内存不够,再次运行 npm install 就好了。
到这一步,原本直接运行就可以,但因为这个服务器上还运行了别的应用,我打算把它部署在子域名下,所以需要配置一下端口和反向代理。如果你没有这个需求,以下三段可以不看。
我安装的是 nginx,因为我对运维也是一知半解,别的服务器怎么写配置文件,我暂且蒙在鼓里。总之,在 /etc/nginx/sites-available/ 下建立 trilium,并写入如下内容:
server {
listen 80;
listen [::]:80;
server_name www.example.com; // 自定义域名
location / {
proxy_pass http://127.0.0.1:8080/; // 自定义端口
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}注意 proxy_pass 必须用 http 协议,否则会 502。
不知为何,我的 /home/[user]/ 目录下并不存在官方说的 .local/share,因此只能自己手动建立一个 data directory:
cd [你要的目录]
mkdir trilium-data
export TRILIUM_DATA_DIR= ~/trilium-data // 设一下环境变量然后把 config.ini 复制过来:
cp <dir>/trilium/config-sample.ini ~/trilium-data/config.ini把这个 config.ini 里的端口改掉,就齐活了。
现在可以运行:
cd trilium
nohup node src/wwwnohup 就是 no hangup,这样即使用户登出,还是能在后台运行服务。在这一步又踩了两个坑,一个是没装 sqlite3,于是手动 npm install sqlite3;另一个是提示 DB uninitialized,只要配置正确后跳转到 /setup 登录完成初次使用导航就好了。
登录和同步完成后,又发现一个问题,就是加载实在太慢。可以调整一下 payload 大小限制,在 server{} 里加上:
client_max_body_size 0;其实我不太确定这一行是不是真的有用,但这么做之后,加载速度可以接受了,就姑且认为灵验吧。
最后,照例 certbot 配置 SSL 证书,就完成了。考虑到看到这一步的朋友多少有些建站基础,在此不赘言。
打开客户端,在「Options/Sync」面板填写远程服务器地址和超时时间(我填了 5000),然后保存,Test sync 看看能不能连上。成功之后,直接用手机登录网页,就可以享受移动端体验。
需要备份时,备份之前建立的 trilium-data 目录即可。
欢迎大家也分享自己的部署经验,给后来人多一点参考和选择。
由于我没有时间钻研写复杂脚本,只改过几个官方插件,本文仅对 Trilium 可以实现的脚本功能进行介绍,抛砖引玉。
前文提到,Trilium 用 attributes 系统来管理各种文件,调度插件脚本。所谓的插件,就是文档树里的一个 js 代码笔记,因此一旦建立了同步,这些插件在各个平台(包括网页、手机)上都可以起效,无需反复安装(在这一点上 Obsidian 不免相形见绌)。
Trilium 给插件提供了前端和后端两套 API,前端在浏览器中运行,主要就是改改界面元素,获取当前笔记之类的;后端则在 node.js 中运行,涉及到数据操作,比如创建笔记、父笔记/子笔记、获取 Label、加密等。根据我的观察,两者之间有一些通用的接口。但在创建 js 代码笔记时,Trilium 会要求你注明是前端还是后端。
然而,仅仅是添加脚本文件还不够。Trilium 不可能在启动时自动运行文档树里所有 js 文件,那既不安全也不合理。所以我们需要告诉 Trilium,这个脚本要在启动时运行。方法是:给脚本文件添加 attribute run,值为 frontendStartup 或 backendStartup。
为了获得更直观的认识,我们来找几个例子。
最简单的插件类型可能就是按钮了——右上角默认有一排快捷按钮,如点击「Today」可以新建或跳转到当天的 day note。我们来看看它的实现原理:
api.addButtonToToolbar({
title: 'Today',
icon: 'calendar',
shortcut: 'ctrl+shift+d',
action: async function() {
const todayNote = await api.getTodayNote();
await api.waitUntilSynced();
api.activateNote(todayNote.noteId);
}
});这段代码给 addButtonToToolbar (顾名思义,给工具栏加个按钮)API 传了一个对象,它由四部分组成:title,按钮文字;icon,按钮图标;shortcut,快捷键;action:点击按钮后的动作,这里面又调用了一堆 API,暂且不作解释。
(真不敢相信,我居然在这篇文章里讲解代码,但来都来了……)
聪明的读者们读到这里应该明白了,我们不用很累很麻烦或懂得 js 代码,就可以通过模仿官方插件做出自己想要的功能。折腾的秘诀,就在于缝缝补补又三年。例如,我现在想做一个快捷键,点击后可以跳转到某个指定的页面,该怎么做呢?
我给出的答案,是大胆抄袭 Weight Tracker 按钮——这个按钮的功能,恰好是跳转到体重统计页面。很好,我们来看看这个按钮的 action 部分是怎么写的:
action: async () => api.activateNote(await api.startNote.getRelationValue('targetNote'))我可以不懂 js,也可以不懂那堆 async/await 是什么意思,但我大胆推测,startNote 应该就是跳转到笔记吧。那么,它到底跳转到了哪个笔记呢?脚本告诉我们,它也不知道,它要去笔记里面找一个叫 targetNote 的 relation,然后跳转到它指向的笔记。
果然,笔记的 attributes 窗口赫然写着:
@targetNote=Weight Tracker这说明,我们只要复制这个 Button 脚本到别的位置,改动它的 targetNote relation 指向的笔记,就可以通过快捷键跳转到该笔记了。
以上是一些适合初涉脚 zhe 本 teng 的使用者的插件魔改思路,当然,掌握了全套 API 后,你也可以写出像官方提供的统计和 GTD 插件一样复杂的脚本,甚至对 Trilium 数据库增删改查(api.sql),一切皆有可能。
官方插件 showcase 在这里,默认笔记里也有一份,可以自行观光。
理论上,你甚至可以写自己的 widget,比如字数统计插件。但我复制了官方的插件,照葫芦画瓢操作一番,并没有成功显示出来,所以很疑惑这个功能是否实装了。如果有尝试成功的朋友请告诉我。
另外,开发者提醒大家,API 还在实验阶段,随时会天翻地覆,所以谨慎使用。
这一节需要一些基本的有关网页的知识。如果对网页的实现原理不了解,简单来说,浏览器负责把 html、css 样式、js 脚本等纯文本文件「解读」成我们看到的样子。
Trilium 是一个基于 electron 的应用,所以视窗相当于一个浏览器,自然可以渲染静态的 html 页面。官方提供了一些范例,例如用 chartjs 实现的体重变化图表:

实现的原理是,在日记模板里定义一个叫「weight」的 attribute,每天填写体重数据。这个页面会通过前文提到的 API 抓取这些数据,然后绘制成图表。
图表页面所在的笔记是一种叫做「render note」的特殊笔记类型,要让上述内容显示出来,要经过如下几个步骤:
renderNote 的关系,并指向刚才新建的 html 笔记这个功能的文档对文件之间的引用关系语焉不详(也有可能是我没找到),所以我凭着自己的经验,并参考官方插件,总结了几条:
@appCss 属性这是一个非常神秘而强大的功能,我还没有找到使用的机会。根据文档的意思,你可以在 Trilium 里定义一个 REST API。什么概念?这意味着 Trilium 可以和其它 app 打通,例如给 slack 写一个 bot,调用你的 Trilium API,输入命令给某个笔记添加子笔记,等等。
要制作自己的 API,首先,建立一个 js 代码笔记,给它添加 customRequestHandler 标签。这个标签的值是一个正则表达式,用来匹配 API 端点的名称(如果你看到这里已经晕了,不用勉强,直接跳过吧)。使用正则表达式的原因是,可能客户端要请求一些带参数的路径,比如官方范例里的 notes/123 ,用正则就可以匹配到所有 notes 后面带数字编号的路径,从而返回对应的笔记。
API 的实现细节也不赘述了,请直接参考上述范例。除了添加笔记之外,可以通过 API 实现分享单篇笔记、甚至接通 gatsby 等静态网站生成器发布博客的功能。但要注意的是 authentication 需要自己实现,防止滥用。
先想到这么多,会慢慢增补。
目前,我个人的工作流完全基于 day note。本来我把网页剪辑都放在一个固定的 inbox 下,后来发现这么做不利于回想当时的上下文,所以改成了默认的方式——剪藏到 day note 下面。
平时,我会写零碎的读书笔记和文本段落,这些统一收纳于 day note 下,晚上整理时,再分门别类 clone 到各自的主题笔记。
这么做的好处是:
day note 的模板我也小作修改,加入了一个链接分区,用于保存当天看到的一些网页书签,日后可以重读。
为了方便收藏书签,我参考这个 gist,做了一个可以复制当前网站标题和链接为 markdown 的 js bookmarklet(方法很简单,添加浏览器书签,填写按钮名字,然后把代码复制到网址栏保存即可),然后在 Trilium 里「paste as markdown」。自从用了这个小按钮,我的心得是——太香了!请有类似需求的诸位务必试试!
另外,在 day note 里 @ 一个项目页面,可以理解为「今天我做了这项工作」。点进该页面的知识图谱,可以直观地看到有哪些 day note 和它关联。如果有空做个插件的话,还能把这份数据可视化为图表,记录项目进度。
每日工作流差不多就是这样,我也不是什么魔鬼,没那么多时间折腾,笔记软件还是趁手最重要。如果大家有独树一帜的工作流,请不吝分享。
最近 Zettelkasten 成了一个很火的概念。莫名其妙的是,我去年九月在网上随机冲浪,就误打误撞冲到了它的官网上,围观了一番,走了。当时,我完全没想到它在 2020 年会火爆如斯,wiki 类笔记工具也有死灰复燃烈火燎原的趋势。
虽然这一切似乎都有赖于 roam,我正式实践 Zettelkasten,却是受到了 TiddlyWiki 的影响(其实,填这个坑的动力也是因为想尽早开始写一篇 TW 相关的文章)。有段时间,我试用了下 TW 的双向链接版本 TiddlyBlink,发现 TW 早在十几年前就有了时间戳笔记的概念,而有了双向链接后,我可以做到:
没错,我现在的 Trilium 工作流就是这么来的。而在这之后我才具体地了解了 Zettelkasten,不得不说真是该死的甜美。它解决了一个至关重要的问题,就是如何化零为整,从底部慢慢建构笔记,用收集的原材料创造未曾有过的想法——而不是先预设好笔记的结构,再进行填充。我大概花了两年时间,才在用 workflowy 的时候想通这一点,找到了适合自己的笔记方式:在一个由碎片构成、缓缓旋转的星辰之海里漫游、连接、组合。
在 Trilium 里实践这个概念并不难,因为快捷键 alt+t 可以直接在标题里插入当前时间戳。接下来的事情就无比自然,利用 clone,我把碎片组合成各种各样的专题,让笔记真正为自己所用。
除了用 clone 整理小纸条外,另一个在 Trilium 里使用 Zettelkasten 的技巧,是「间接引用」。例如,对于网页剪藏下来的内容,可以在时间戳笔记里 @ 它,记录心得体会。这样就能在知识图谱里看到自己对一则素材在不同时间点产生的想法。
之前有朋友评论,希望能对比两个软件。嗯,我确实也试用了 obsidian……
先回答评论里提的问题吧,Trilium 能不能模仿链接到块的效果,据我所知并不能。 Trilium 本身并不是一个以双向链接为卖点的笔记软件,它只是在知识图谱里显示出和当前笔记相关的一些笔记(如果点进 show full 再调高显示的笔记上限,可以看到并不是和这则笔记直接相关的笔记也包括在内)。另外,理论上,在 Trilium 里可以写迷你笔记(块),再用 Book View 统一浏览。也就是说,手动调整笔记粒度。但因为无法同时看到多条笔记(而 TiddlyWiki 可以),这个功能略鸡肋。
说回 obsidian。这个软件很有潜力,只要它能做到编辑器所见即所得。它采用纯 markdown 单文件格式,这意味着一个 obsidian vault 可以直接喂进静态网站生成器里(比如这个超赞的 digital garden generator),变成博客或别的形式。obsidian 是输入输出兼备的利器,而 Trilium 更适合做输入和消化端(考虑到极其方便的剪辑功能,和颇费一番功夫的导出)。
和 Trilium 的全能相比,obsidian 似乎更想「做加法」,提供最基础的功能,然后用插件慢慢堆上去,粗粗看了下甚至有渲染成幻灯片、记忆卡的插件。和 Trilium 的一体化相比,obsidian 是一个非常灵活松散的工具。举个例子,你甚至可以在一个 vault 的子目录下面打开另一个 vault。vault 根本上是本地文件系统的浏览器,加上了插件后,它还可以是自定义标记语言的渲染器。我觉得它的野心很大,可能要像 devonthink 一样,朝管理整个文件系统发展。而无论是 Trilium 还是 TiddlyWiki,甚至 roam,都是沙盒式的知识管理软件,在自己的小天地里玩耍。
选择一个笔记软件,往往就是选择了一种工作方式,强行魔改自带功能可能并不是一个好想法。obsidian 的潜力就在于,它就像用户 DIY 组装机,可以自由选配自己需要的插件。我比较期待它能有分享插件配置文件、一键安装的功能,因为现在自带的插件配置起来已经很麻烦了。
最后说说两个软件在设计和使用思路上的共同点:它们都要求用户决定一则笔记在文档树中的位置。不像 roam 和 TW 建立的笔记可以遗世独立,抛在脑后,这个选择新建位置的设定(至少对我来说)是额外的心智负担。在 Trilium 里我用 day note 来绕开这一层,而 obsidian 则可以用它内建的 Zettelkasten 插件,把笔记临时丢在一个「盒子」里。
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。