下文大致译自我的这篇博客 。
大约在 5 年前,我尝试在 GitHub 上做个人博客。那时我对任何标记语言都不熟悉,所以我就手工写 HTML 页面然后在浏览器里调 CSS 效果进行排版。顺带一提,那并不是学习 HTML 和 CSS 的好方式。总的来说,我当时在 W3School 学习 HTML 和 CSS,那时我还不知道 MDN (MDN可能不是那么好查,但至少是一个文档),只知道 Mozilla 是 Firefox 的创造者,但那时我并不使用 Firefox。我当时还向往着成为一个在 MS Windows 上破解应用程序的经典黑客,对万维网上发生的变化一无所知。这些页面如今存储在我的备份硬盘上,没什么特别的。所以我预期 5 年后,新写的这些页面也依然躺在某个硬盘里面,没什么特别的。
我已经用 org-mode 写文章大约 3 年了,零零散散差不多有百万字了。我转向 org-mode 的主要原因是 Typora 在 GitHub 上停止了发布新的免费版本。当时我还是个穷学生,一时找不到像 Typora 那样好用的 Markdown 编辑器:支持所见即所得、支持 \LaTeX 预览、支持主题 HTML 导出(我为它设计了几个主题)。所以我强迫自己学习了 org-mode(那时我已经接触 Linux 和 Emacs,并把 Emacs 作为我首选的代码编辑器)。很快我发现 org-mode 很强大,有一些杀手级功能,比如 org-babel、org-table 和 org-export。这些功能可能不是完美无缺,但对用户来说非常有用。习惯了 org-mode 之后,你会觉得自己站在世界之蛇的中央,既看不到头也看不到尾。
对我来说org最重要的功能是 \LaTeX 嵌入支持。我的学校作业有一定程度的数学内容,需要一个良好的 \LaTeX 环境来记录笔记。虽然 Emacs 有 AUCTeX,但是那时我也不够聪明,搞不明白怎么使用这个复杂的环境。所以我仍然用 org-mode 编写大多数的数学公式。
言归正传,我们知道,ox-html 解决了如何把 org 文件导出为带自定义样式的 HTML。而且,它允许我们自定义 CSS 样式支持。此外,通过htmlize包的支持,我们可以用org-html-htmlize-generate-css一键导出当前的Emacs主题,这也省去了我雕琢 CSS 的麻烦,只需要生成一个小石主题然后输出成 CSS 样式表就行了。可惜的是生成的样式使用的仍然是 Emacs 里的 face 名称而不是CSS class名称,需要手工修改,不然我还可以时不时换个主题。ox-html也提供了Mathjax支持,Mathjax实际上只能提供一个小的 \LaTeX 子集,聊胜于无,至少节省了很多储存公式图片的空间。至于不支持的 \LaTeX 环境,好吧,我木得主意。
解决了如何生成html的问题,接下来就是如何持续集成和发布。确实有一个名为 org-publish 的模块提供一个简单的发布框架,但我感觉它不适合我。我有太多 org 文档保存在 roam 数据库里,我不想维护一个要发布的文件清单。我只想把这些已发布的页面扔到某个地方,如果需要更新就覆盖它们,然后用 rsync 上传到我的服务器上。或者说我不想要维护一个 Makefile,我不想写 Makefile 解析器。对我来说 html 才是源文件,构建就是用rsync命令增量上传。
于是,对于网站架构,我看到了两个选项:
完全静态站点 :所有页面都是编译输出,要更新某个页面需要重新编译其源文件。这需要某些工具维护源和目标之间的映射,这正是 org-publish 做的事情。
动态生成站点 :我们把 JS 嵌入页面,使得完整内容可在运行时生成,这更高效、更优雅。但这要么要求浏览器支持 JavaScript(前端计算),要么要求服务器提供比文件服务器更多的 HTTP 服务(后端计算)。
出于服务器性能的考虑,我想我只能维护一个纯静态站点,或者只有前端计算的动态站点。但问题是我不想维护源文件。同时,我仍希望它兼容像 eww 这样的文本浏览器,所以不偏好 JS。然而,手动维护站点地图(sitemap)也很烦人(后面我会解释具体原因)。最终我妥协了,用 JS 生成 sitemap。对那些使用 eww 的人来说,我想他们应该知道如何解析 index.json 并找到所有页面路径。如果不知道,那是 HTML 设计者的责任,不是我的。
至于 RSS 订阅,我从未觉得它对我有意义。我只从 hackernews 读取 RSS 订阅。另外,Emacs 没有提供高级的 XML 库,它的 xml 只能在字符串层面工作而不是 DOM 对象。好吧,我实现了一个生成 RSS 的函数,只是为了好玩。我之所以选择把站点地图保存在 index.json 而不是 sitemap.html,原因也是一样:Emacs 的 JSON 库是对象级库,你可以把整个文件作为一个 JSON 对象修改,而 XML 就不行。虽然有像 libxml-parse-xml-region 和 libxml-parse-html-region 这样的解析函数可以产生真正意义上的 XML 对象,但是 Emacs 没有提供好的 XML 序列化函数(xml-print主要用于调试打印,而非序列化)。
另一方面,我认为动态生成 sitemap 并不是那么糟糕,至少这可能阻止一些机器人的访问(已经过ChatGPT验证,拦截有效。实际上最初为了防机器人,我专门找了一个基于挑战的人机验证插件,现在看来还用不上)。
我的发布工具可以在koishimacs:publish 一节找到。
(欢迎大家来扩列)
8 个赞
我的博客:Taxodium
我也是 org-publish 实现的,相关文章见:
实现代码:
关于 RSS,如果可以最好提供,给读者多一个关注你的渠道,毕竟读者未必有时间总是来翻你的博客,看看有没有更新。
RSS 之前我也是找了个 Elisp 包实现的,但发现文章多了,性能不是很好,后来是用 JS 重新写了一下,在构建时执行。
如果你想把 RSS 弄的好看一点,这里有一篇文章:让你的 RSS/Atom feed 更好看
你的博客我看了看,有个小建议,博客的音乐或许不要默认打开?
我在听歌,突然一段音乐出来,会比较干扰我。或者考虑页面上添加一个开关,不然读者只能静音正个 tab 才能关闭了。而且这段音乐,每切换一个页面都会重置播放,体验似乎也不是很好。
当然,博客是你的,你喜欢怎么样都行 ,我只是作为一位读者表达一下我的想法~
4 个赞
Spike-Leung:
我也是 org-publish 实现的
看的不仔细,我没有用org-publish哦
我用libxml2实现的RSS生成,应该不会有性能问题。我不太想用JS生成订阅,因为我的后端只有一个静态文件服务器,而订阅请求不一定是从支持JS的前端发出的。比如说订阅可能是用链接直接请求你的RSS文件,我的情况应该不太能满足动态生成吧?
我打算以后把制作的音乐放到电台部分,这个按钮只是用来提神的。有没有惊喜的感觉?
哈哈哈,确实看的不够仔细,我再看一次!
所以你的方法就是 ox-html 负责生成,然后 rsync 上传?
org-publish 也是调用 ox-html 去把 org 渲染成 html 的,你是相当于自己实现 org-publish 相关功能咯?
是的,因为我无法定义一个org-publish project,我的org文件在本地是用roam松散组织的。大概有几百个,如果梭哈的话要处理的路径太多了,还是单点发布比较妥当。
关于你说的 RSS 部分我没太看明白啦。
你的意思是你只想丢一些静态文件到服务器,服务器不做其他处理逻辑,所以 RSS 生成不太好搞?
因为我是丢到了 Netlify 后,每次推送触发构建,然后生成 RSS 的 XML 的,如果不想在服务器上做,那可能就是每次写了新文章,本地运行生成 RSS 再一起推送就好?
不管如何,我觉得生成一份能够订阅的 RSS 是好事,至于怎么做,能生成出来就行。
然后是关于文件太多,org-publish 不太好选择文件进行处理的问题,我不太记得 org-roam (你说的 roam 应该是它吧)会不会给文件名上打标签了,如果会的话,根据标签过滤应该还挺方便的。
我是用 denote,denote 会在文件名上写入 filetag,然后我就可以根据 filetag 过滤哪些文件是可以发布的,哪些是草稿,哪些压根就不处理。
(setq org-publish-project-alist
`(("orgfiles"
:base-directory "~/git/taxodium/posts"
:base-extension "org"
:exclude ".*"
;; 例如这里,我过滤了带有 _published tag 的文件,denote 也提供了方法进行过滤
:include ,(spike-leung/get-file-list-from-denote-silo "~/git/taxodium/posts" "_published")
:publishing-directory ,spike-leung/org-publish-default-publishing-directory
;; 省略其他配置....
)))
是的,但是我不常写 JS,更不想在本地跑 JS 脚本(因为 JS 本来就不是在本地跑的,nodejs 这种依托v8core才有文件系统访问服务),所以就全交给 Emacs 处理了。
是的。标签机制和org没有关系,是org原生的服务,roam是会自动生成一个包含roam id的property,但我并没有为了发布专门打过标签。而且我的org文档也不全是roam管理的,所以最后实现就是不要org-publish,用单点+rsync。
这样子,anyway,能跑起来发布就行,哈哈哈,怎么舒服怎么来
老实说没考虑那么多,就这点东西忙了我一周。现在我是纯纯玩泥巴的感觉
生成 RSS 是把路走窄了,我 RSS 内容都是手写更新的,当成微博用
1 个赞
我的更新模式是增量更新,除非需要覆盖原来的feed,并不抗拒手写。
好家伙,你的意思是把 RSS 当微博用,有事没事写点东西,而不是限制在生成文章更新上?
思路打开了
我是从 fediverse 分布式社交媒体用的 ActivityPub 协议受到启发的,实际上 Atom/RSS 就是个单向版本的 ActivityPub
我也用过,主要感觉还是不够灵活,它的增量式更新用了绝对路径,缓存文件换个机器就不能用了。
gynamics:
对我来说 html 才是源文件
qs,本地生成然后上传只要规模不大完全管的过来。我现在在用 Cloudflare page,把生成的 HTML 和资源文件放到 git 然后不断 push 就能更新网页了,很方便。
2 个赞
哇,还有git工作流。
我用git管理主页html和js,但是二进制resource和生成的post都ignore了。感觉git本身起的作用并不大。
利用cloudfare page的自动构建,把源码放在git上,既避免了本地构建,又可以规避github静态站在网络不稳定的问题。
1 个赞
David
2026 年2 月 3 日 02:46
17
我现在日常使用Newsboat看RSS,觉得标题或摘要有点意思的情况下才会用浏览器打开网页看看。可能是人变懒了。
那真是太不幸了。我没有做给post生成description。不过我可能会学ldbeth写description当围脖发。
在浏览器里专门打开链接看技术博客逐渐变得很奢侈,我会觉得读文档或者代码更直接。所以我的文章也不太属于正经的技术博客,但大概没什么人能对上电波。
手写感觉不太方便呀,大佬是怎么操作的,有没有空分享一下👀
之前用 org-publish 写博客,找到一个生成 rss 的包,需要把所有内容写在一个 org 文件里,按照 heading 拆分成 rss 条目。
我在想,是不是可以结合 datetree(用 capture 可以很容易生成),在一个 org 文件里记录随想(当作朋友圈),然后按照 datetree 的日期生成 rss,用来分享一些零散的想法似乎还行
用 Invisible XML 工具从自定义标记语言生成的 XML
Thu, 12 Jan 2023 16:28:45 CST
CLtL2 ebook avaliable #Book
https://ldbeth.sdf.org/cltl2.html
===
<p>The original book was out of print long time
ago. The avaliable ebook version is prepared by someone with
limited knowledge of TeX and typesetting, and the LaTeX files
available is not compatible with modern LaTeX version. So I
made some effort to make a well typeset PDF version
available again.</p>
---
id: https://ldbeth.sdf.org/cltl2.html
.
Mon, 26 Dec 2022 15:49:51 CST
Atom feed for my anime list #Articles
https://ldbeth.sdf.org/articles/anime.xml
===
<p>I'm comparing RSS 2.0 and Atom 1.0 so the
new feed is in Atom format.</p>
---
id: art#2
.
Sun, 25 Dec 2022 14:46:26 CST
RSS XML Grammar #Emacs, #XML
https://github.com/LdBeth/InfernoEmacs
===
<p>I have made a RelaxNG grammar for RSS 2.0, so
one can now edit RSS XML file with Emacs.</p>
---
id: emacs#1
.
1 个赞