构建自己的笔记博客系统(程序员版)

很多程序员都有做笔记的习惯,而且会写个人博客和公众号。但是怎么管理笔记、什么平台写博客、怎么快速编辑公众号,一直是个大难题。在走了多年弯路之后,我找到了一套自己的方式,可以把学习笔记、博客和公众号高效整合起来。这篇文章本来去年就该写的,但是由于比较忙+拖延症一直没写。最近突然觉得有必要分享一下,希望能帮助更多人从中找到启发,早日摆脱繁琐的笔记和博客的编辑和管理。

我的诉求

关于笔记和博客,我有一系列的诉求,并且可以说有点苛刻了:

1、笔记编辑方便。我现在写文章基本都是优先使用Markdown,所以笔记软件要支持Markdown,我经常会在笔记里插入代码片段,而且很喜欢放图片,还有时候可能会从网上复制粘贴一段带有格式包括图片的文字,因此Markdown编辑过程中的流畅性也很重要。只能在线编辑的笔记工具都不考虑,因为严重依赖网络,网络不佳的时候就没法查看和编辑笔记了,没有安全感,且很多在线软件的体验不太好。

2、笔记数据可靠。很多人用商业笔记软件,例如印象笔记、有道云笔记,以及我之前用的为知笔记。但是有个问题,这些笔记软件可能突然改版了难以使用,或者是收费变高,更坑的是突然通知停止维护了,这时我会考虑要不要换个笔记软件,又很担心自己辛辛苦苦写的笔记没了。最理想的方式是笔记软件直接用公开的Markdown之类格式保存,数据完全掌握在自己手里。或者至少笔记软件中可以导出通用文档格式,方便我随时迁移到其他笔记软件中。另外笔记最好支持版本管理,我很少会误操作,用的不多,但是感觉关键时刻会很有用。

3、笔记管理方便。因为我笔记很多,且有不同的大分类,希望以多级文件夹的形式组织,要是还可以支持标签就更方便了。另外笔记要能按标题和全文搜索,这是基本要求。

4、笔记和博客打通。把笔记分为私有和公开笔记,私有笔记是给自己看的,公开笔记则要能同步发布到博客和公众号,并且之后的修改也可以同步到博客(由于公众号文章发布后只能改错别字,就不做要求了)。我不希望在本地编辑好了之后,又要在博客和公众号上分别再复制粘贴排版一次,特别是图片上传还得一张张插入,实在浪费生命。两类笔记可以存放在同一个地方的不同子目录,一些文章在整理阶段算私有笔记,整理好了又能马上移动到公开笔记目录同步到博客。至于博客,需要支持最常见的评论、搜索等功能,且可以根据自己的喜好改网页样式。

5、笔记的同步和跨平台。由于平时会用到多台电脑,以及平板、手机,所以需要在不同设备之间同步笔记,且笔记软件要支持全平台(Windows / Mac / Linux / Android / iOS)。具体到桌面端和移动端,把笔记分为文章和备忘两种类型,文章通常是复杂的长篇大论,主要在电脑上编辑,手机上主要是阅读或者细节完善,而备忘则是比较简短零碎的文字,可能是最近要做的事情备忘录,也可能灵感来了用手机随手记点笔记之类,且备忘类都是私有笔记,不需要发布到博客上。

根据这些诉求,对比了众多笔记软件,研究了各种方案。

1、笔记编辑方便

多年前还在上大学时,我用Word写过文章,然后转成PDF,但是排版和文件版本管理都很繁琐,只能说勉强可用,完全谈不上优雅。

后来用国产的为知笔记,我在博客里还给为知笔记写过几篇文章各种夸。之后为知笔记突然就开始收费了,这倒也没什么问题,作为为知笔记资深用户,我果断付费了。为知笔记的编辑功能还是偏向于富文本编辑器的设计,虽然可以设置丰富的格式,但是对于Markdown的支持并没有特别好,且由于富文本格式过于复杂,为知笔记编辑器里的Bug挺多。有一点要感谢为知笔记的是,我最开始知道Markdown就是因为为知笔记里的新特性介绍。

之后工作了,更加没有精力在排版上浪费时间了,年纪大了对花里胡哨的排版也更加不感兴趣了。有很长一段时间我都在直接用Markdown写文章,然后用git管理写好的Markdown文件,一开始的编辑器是跨平台且免费的Haroopad,之后被同事推荐发现了宝藏编辑器Typora。而为知笔记更多的被用于记备忘,因为为知笔记在手机和电脑上同步很方便,而备忘常常是突然想到一些事然后就用手机记录的。

Typora相比其他众多Markdown编辑器,有几个很重要的特点。Typora支持所见即所得的编辑模式,不需要左边写Markdown源码右边显示预览,而是两者合二为一。插入图片时,可以在界面上直接粘贴,Typora会自己把图片复制到指定的目录,这就比常规的自己保存图片、然后手写Markdown引用图片的方式轻松多了。还有一个点就是Typora还能粘贴网页上带格式的富文本,自动转换成Markdown,当初着实让我震惊了一会。加上Typora优美的界面设计和可更换主题设计,以至于后来他们开始在新版本收费了,我也没有太犹豫就付费支持了一波。

2、笔记数据可靠

给人安全感最高的笔记数据保存方式,就是直接以文件的形式保存在本地,且文件格式是公开通用的Markdown格式。这样即使一个笔记软件用不了了,也可以无缝切换到其他软件查看和编辑。

Markdown笔记在编辑和发布的时候,有个很麻烦的事情是图片。一种比较优雅的解决方案是使用PicGo之类工具,可以在你本地复制了一张图片或者截屏后,自动上传图片到CDN服务器、生成URL、把对应的Markdown源码拷贝到剪贴板,你要做的就是直接在Markdown编辑器里粘贴。发布到博客的时候,由于图片本来就有完整URL,所以也不需要担心图片怎么上传到博客的问题。

但是我对这种方式并不满意。虽然博客文章本身是安全了,但是图片还是存在CDN服务器上的,并不安全,可能哪天服务器要关停了,那么多笔记图片想全下载下来实在艰难。

所以我始终坚持把图片保存在本地,放在Markdown文件平级的images文件夹里,而Typora刚好有这个功能,这让我非常满意。

3、笔记管理方便

Typora解决了Markdown编辑的一些麻烦事,但是对笔记的管理能力比较弱。虽然Typora也可以打开一整个包含很多Markdown的文件夹,但是也就仅此而已,没有更多和笔记管理有关的功能,例如不能进行全文搜索。

实际试用了很多种支持Markdown的笔记软件,包括Wolai、思源笔记、VNote等,直到用了Obsidian,有种相见恨晚的感觉。

  • Obsidian和VSCode一样,都是基于Electron开发,所以天生自带跨平台属性,且两者操作逻辑很相似,很容易上手。
  • Obsidian支持安装主题,窗口可以灵活调整,支持Tab和无限分栏,还可以把Tab拖出来创建一个很纯净的窗口专注写作。
  • 常规的文件管理和搜索功能都不在话下,快捷键丰富且支持自定义,可以调出命令菜单搜索运行各种命令,并支持丰富的插件扩展,功能灵活又强大。
  • Obsidian软件本身是免费的,提供了一个可选的付费数据同步服务。

笔记编辑上

  • Obsidian支持Typora一样的编辑模式,编辑体验和Typora差不多。
  • Advanced Tables插件可以辅助编辑Markdown表格,自动对齐每一列,比Typora更方便了。
  • Markdown Prettifier插件可以格式化Markdown。
  • Pandoc Plugin插件可以把Markdown笔记导出成PDF、Word等格式。

笔记管理上

  • Obsidian会打开一个文件夹作为笔记目录,且所有的配置也都存放在这个文件夹下的.obsidian目录。只要把这个目录用git管理起来,迁移到新电脑上非常容易。
  • Obsidian可以管理笔记,文件夹可以嵌套,支持全文搜索,支持双链笔记,支持标签管理。
  • Quick Switcher功能可以快速通过标题搜索笔记并打开。
  • Consistent attachments and links插件可以设置把文章的图片都放在平级的images目录中,如果移动笔记,对应的图片也会被移动,这个非常有用,我甚至为有人跟我想到一样的使用需要并且已经做了实现感到震惊。不足之处是处理有点慢,需要等。
  • Unique attachments插件可以重命名文章中的图片为MD5,更加整洁。
  • Clear Unused Images插件可以自动清除没有被文章引用的图片。
  • Terminal插件可以打开一个shell窗口,从而方便运行git命令管理笔记。
  • Open vault in VSCode插件给界面上加了个小按钮,点一下就可以用VSCode打开笔记目录,这时就可以用VSCode对笔记Markdown源码做一些更高级的操作了,例如正则替换。这也是使用开放格式的笔记软件的好处,可以同时用多个工具编辑笔记。
  • Obsidian官方提供了付费的Sync功能,可以在不同设备之间Sync,这样移动端也就可以编辑笔记了。不过我是直接用git管理笔记的,就没有用这个功能。

4、笔记和博客打通

我之所以用为知笔记,还有一个很重要的原因是为知笔记支持把笔记一键发布到WordPress等支持MetaWeblog的博客。但是为知笔记的博客发布功能有几个问题。

1、发布过程繁琐。为知笔记发布博客原本很简单,前提是文章在为知笔记里写的,且用的Windows版本。但是在我经常用Typora+Markdown写文章之后,每次想发到博客,就需要把文章复制到为知笔记里,最麻烦的一步是图片需要一张一张重新插入。另一个问题是只有Windows版为知笔记有发布功能,所以我经常要先在Mac里写好笔记,然后在Windows虚拟机里启动为知笔记,同步数据,再发布到博客。

2、更新博客困难。为知笔记会把发布出去的笔记的博客id缓存起来,在没有重装的情况下,重新发布就会更新已有博客。但是如果系统重装或者换了电脑,就失效了。还有个巨大的缺点,就是每次编辑都会重新上传文章里的所有图片,导致我的WordPress服务器里有很多无用图片,这些硬盘都是我花钱买的,感觉也很亏。

为了解决这个问题,我花费了很多精力去研究Markdown发布博客的技术实现。网上有人提供了一些看似优雅的办法,通过pandoc命令行渲染Markdown然后调用MetaWeblog的API发布,但是实现太过简陋,基本的笔记属性都设置不了,且不能解决本地图片上传到博客的问题,除非使用前面说的PicGo在编辑时就把图片传到CDN服务器,而这不是我想要的。

后来我花了两个多月的时间,基于Electron自己做了一个专门发布文章到博客的开源工具,取名为PublishMarkdown。这下开心了,我再也不需要用为知笔记来发博客了,而且也不用担心为知笔记里编辑博客需要重新上传所有图片的问题,因为这个工具会对图片做md5,把每张图片上传后的id也给存起来,重新发布的时候会据此自动处理。但是同样的问题,如果是在多个电脑上用或者重装系统,这些缓存的id也就没了。

PublishMarkdown项目的GitHub主页:https://github.com/jzj1993/PublishMarkdown

之后还是觉得WordPress对Markdown的支持没有那么好,加上PublicMarkdown这个工具有时候会有一点小Bug且使用体验不佳,整个过程还是不够优雅。所以还是决定迁移到Hexo上,用GitHub Pages来保存网站内容,这样还可以节省每年几百块的VPS服务器费用。Hexo的搜索可以使用hexo-generator-searchdb插件实现local search,阅读量统计和评论可以使用Valine实现。

由于Obsidian的笔记保存方式是直接在文件夹里放Markdown(假设路径是Notes),所以我在里面单独建了一个Notes/blog目录,把所有要发布到博客的公开笔记都移到里面(这个时候Consistent attachments and links插件就发挥作用了,会自动把笔记引用过的图片也移动到同级目录)。

我又在Blog目录创建了一个Hexo博客工程,这个工程里有Hexo的各种配置,包括被我魔改过CSS的Next主题。

正常情况下,博客源文件要放在Blog/source/_posts中,我将其软链接到了Notes/blog目录,这样Hexo工程就可以直接读取要发博客的Markdown笔记源文件了。

文件夹结构

1
2
3
4
- Notes
- Notes/blog/
- Blog
- Blog/source/_posts -> Notes/blog/

Hexo发布文章通常分为几步:

1、hexo clean清空public目录
2、hexo generate把Markdown源文件渲染成HTML输出到public目录
3、hexo server可以在本地启动静态文件服务器,预览网站效果
4、hexo deploy把public目录中的文件push到Github

在第二步渲染时,Hexo原先的设计要求所有文章的图片都在同一个目录,没办法正确处理Markdown中用相对路径引用的图片。因此我在hexo-renderer-markdown-it基础上魔改了一番,在渲染时会自动把相对路径引用的图片复制到public目录中的对应位置,并且会跳过重复图片,同时在渲染输出的HTML中用相对路径正确引用图片。

第一步clean不是必须的,通常可以省略,这样Hexo每次只会渲染有改动的文章,耗时大大减少。

第四步deploy时,默认的实现会重新push所有内容覆盖到Github,但是博客里的图片数量众多,这样push会非常慢,有必要改成增量。

因此我写了一个deploy.sh脚本,每次将远程最新的博客HTML文件(包括图片)更新到remote目录,然后用软链接把remote/.git链接到public/.git,这时git就会认为public目录也是一个git项目,且HEAD指向了远程博客HTML文件的最新版本,于是就可以利用git计算出当前的public相对HEAD的文件变更,提交一个只包含变更的commit并push到远程,从而实现增量更新博客,大大提高了博客发布性能。这里之所以要单独开一个remote目录然后软链接,是因为public目录可能会在clean时被完全清空,所以不能把git repo直接克隆到public里面。

之后无论是往blog目录增加新文章,还是修改blog目录已有的文章后,都只需要运行一下deploy.sh就能增量同步改动到博客,不需要担心重复创建文章或是重复上传图片的问题,因为hexo和git已经帮我们处理好了。换电脑也没关系,只是第一次克隆到remote目录会比较慢,之后也同样可以增量更新了。

文件夹结构

1
2
3
4
5
6
- Notes
- Notes/blog/
- Blog
- Blog/source/_posts -> Notes/blog/
- Blog/remote/.git
- Blog/public/.git -> Blog/remote/.git

博客工程的源码也放到Github上了:https://github.com/jzj1993/jzj1993.github.io

微信公众号上发布图片笔记也比较繁琐,需要自己一张一张的插入图片,这一点也被很多人吐槽过。但是如果文章已经发布到网上,就可以直接复制粘贴到微信公众号编辑器里,编辑器会保留文章的CSS样式,并且自动从对应的URL下载图片插入到文章里。因此也不需要手动去编辑文章了。所以只要博客本身的CSS样式不算太丑,直接复制到公众号里也完全没有问题。

5、笔记的同步和跨平台

由于Obsidian使用文件夹和Markdown文件保存笔记,因此在不同的设备上直接通过git管理,就可以实现笔记的同步了。不过这样手机上就不方便同步数据了,可以使用Obsidian Git插件在手机上同步数据,但是有一定的限制,我目前还没试过。

前面说了,我把笔记分为文章和备忘两种类型,Obsidian里保存的主要都是文章类型的笔记,通常比较复杂,我基本都在电脑上编辑,偶尔想在手机上看就导出PDF。而备忘型的笔记,常常要同时在手机和电脑上编辑查看,字数不会很多,格式也不会太复杂,所以我直接用微信收藏功能解决了。如果备忘越写越完善,必要的时候,也会整理成文章放到Obsidian里。

跨平台问题前面也已经说过了,Obsidian是基于Electron开发的,所以本来就支持Desktop全平台,而Obsidian也提供了Mobile版本。所以跨平台不成问题。

总结

在我的各种魔改之后,现在的我终于可以把时间精力都专注于写作本身了,而不是整天在排版、笔记管理、发博客这些事情上纠结。现在的方案也全面拥抱开源、透明、免费、轻量化的技术了,除了每年要给域名花点钱,其他都是免费的。

为了迁移到这样一套系统中,我费了很大力气把以前存在为知笔记、WordPress博客上的内容全都做了迁移,用了一些Hack手法,都是技术细节,我在另一篇博客里有介绍,这里就不讲了。

这里把整个写笔记和发布博客公众号的流程再做个总结。

1、笔记编辑:首先我可以在Obsidian里用“所见即所得”的方式专注于Markdown的编写。图片和网页内容都可以直接粘贴,Obsidian会自动处理排版,并把图片保存到同级images目录。写好了还可以用Markdown Prettifier插件整理Markdown格式。

2、图片整理:写完之后,我可以用Clear Unused Images插件清除写笔记过程中插入但是最后又没用到的多余图片,用Unique attachments插件把图片重命名为MD5格式,更加美观统一。如果觉得图片比较大想压缩一下,节省储存空间特别是博客上的加载速度,或者是想加水印,因为图片都在本地文件夹,有很多工具可以实现。例如可以把images目录拖到ImageOptim软件中,就会自动无损压缩图片并替换原始文件。

3、发布博客:文章写好了,如果我想发到博客,就移动到Notes/blog子目录,我可以按照自己想要的方式组织这里面的文章,可以放在这个子目录里的任意位置。Consistent attachments and links插件会自动同步的把文章引用的图片移动到Markdown同级的images目录下。然后用Hexo的Front-matter格式,在Markdown顶部用YAML语法指定文章标题、时间、分类、标签、固定链接、是否置顶等参数。最后,在命令行里切到Blog目录,运行./deploy.sh,就会自动把Notes/blog中的更新以增量的形式快速同步到Github Pages。几分钟后,我就可以在网站上看到自己更新的博客了。之后如果编辑已有的公开笔记,也只需要重新运行一下deploy.sh就同步到博客上了。

4、发公众号:发布到博客后,在网页上复制全文,直接粘贴到公众号的编辑器窗口里,然后填一下标题、作者、封面图信息,点击预览在手机上检查一下效果,最后点击发布推送给用户,就可以发群聊发朋友圈求点赞了。

5、笔记分享:可以用Pandoc插件的导出功能,把Markdown导出成HTML / Word / PDF文件分享给其他人。

6、笔记同步:在Obsidian的Terminal插件提供的窗口中运行git命令,把最新的博客push到私有git仓库。也可以选择用Obsidian Git插件把数据同步上去。在其他设备上通过git再把变更同步下来。

7、备忘录:对于待办事项我会用Any.Do、Google Calendar之类软件,对于需要做简单笔记的备忘录(比如最近旅游计划,今年年终总结的提纲),直接在微信收藏中编辑就可以了,手机电脑都能编辑,必要的话再迁移到Obsidian里。