使用 Emacs Org-Mode 构建博客

最近受够了 Hugo + Org-Mode 的工作流:首先使用 ox-hugo 导出至 Hugo 兼容的 Markdown 格式,你需要折腾 Org;由于用了 Hugo,你需要折腾 Hugo 的 cofig、theme等一系列问题;最后你还得折腾 CI 以在托管构建项目。

同时,Hugo并不具备很强的配置性:基本上只能维护一个 Blog 列表以及独立的 index.md,如果你需要不同的子结构则需要一系列的 Hacking 。更重要的是,如果你希望手动嵌入一些手写的 html 页面,则需要在 Hugo 构建之后手动注入。

加上希望从 Github Pages 迁移至 Cloudflare Pages ,决定使用 Pure Emacs 工作流重构博客。

折腾记忆

昔者 庚子 (高三) 岁暮,值黉门季考之期,众生皆困于铁幕。凡传讯之器尽缴,寰宇之网尽绝,恍若堕无何有之乡。然有二三子耽奇好异,竟于绝境中辟得桃源——或以刀笔刻竹为戏,或以素楮录异为乐 (写日记)。中有孙生者 (最魔怔的一个) 尤擅诡谲之文,其札记光怪陆离,观者莫不拊掌称奇 (大嘘)。

洎壬寅升太学 (本科时间多啊) ,时宽事简,遂纵情于札牍之道。尝于冲浪之际偶遇某博(惜其名已湮,大概是分享 FP 的),见其藻饰若璇霄丹阙,椠术类鬼斧神工。适余方沉酣Qt之戏,醉心于方寸之规,乃决意自筑文囿。初择 Hexo 氏之格,假 Github Pages 之台以栖,务求华衮之饰:或置案头小灵为伴,或设云车幻转入界,致访客每候十息方得窥全豹 (CSSJS 怎么 花哨 怎么来) 。然多耽于椠术之嬉,鲜有著述之实,所录无非 C++ 玄言、 CUDA 秘术,兼少年绮靡之思 (我又幻想了…),今观之犹赧然汗下。

old-hexo-blog.png
Figure 1: Old hexo blog screenshot

既而癸卯改弦,弃 Neovim 如敝履,转奉 GNU Emacs 为圭臬 (圭臬中的圭臬!) 。习得纲目之法,始以经籍之体录日记、理庶务,遂萌易辙更张之念。时人皆推 ox-hugo 为良媒(当然现在 Hugo 原生支持 Org-mode 了),乃迁 Hexo 之巢入 Hugo 之穴。讵料初度劫波竟至,莽撞删刈旧博,如焚阿房三百里,至今思之犹扼腕( 然中二言文之绝迹,岂为祸哉 )。

如是经营期年,屯文十数篇,方期渐入佳境。忽逢二度劫波:台阁崩摧,欲重修栈道之际,孰料旧舟竟朽,文牍尽没于苍茫云水间。嗟乎!昔韩昌黎祭鱼之文尚存副本,今余之札记竟如石沉大海,岂非天欲磨书生狂狷之气耶? (电脑进水之第二次大冲击)

折腾目标

  1. 轻量级且可高度 DIY
  2. 没有外部软件依赖

工具

编辑器 GNU Emacs
编辑语言 Org-mode
Site Generator ox-html.el & ox-publish
网站托管 Cloudflare Workers Site

使用 ox-html 导出 html5

org-mode 原生支持各种格式的 导出 ,你可以通过 org-export-dispatch 函数打开一个导出分派器的 ui,并在里面选择各种导出选项。这里给出博客导出设定的 snippet,具体导出设定请见 org-mode manual 13.9 1:

#+TITLE: Article Title

#+OPTIONS: toc:nil H:4 ^:nil pri:t
#+OPTIONS: html-style:nil
#+OPTIONS: html5-fancy:t
#+HTML_DOCTYPE: html5
#+HTML_HEAD: <link rel="stylesheet" type="text/css" href="org.css"/>

#+BEGIN_abstract
Article abstract.
#+END_abstract

#+TOC: headlines 2

Your content goes here.

这里选择导出为 html5 格式并关闭了默认导出的 css 和指定了博客的 css。

使用 ox-publish 构建博客

个人认为 ox-publish.el 实际上相当于 Makefile,所谓 publish 就是根据源文件生成一些文件并移动到构建目标。这里参考 Thomas Ingram 2的博客。我的博客使用以下 project structure

~/fuloido.moe/
├── src/                    # blog source files to be exported
│   ├── notes/
│   │   ├── index.html      # `notes' pages directory
|   |   ├── note-style.css  # note specific css
|   |   ├─- note-script.js  # note specific script
|   |   └── example-note/
|   |       ├─ example.png
|   |       └- example.org
│   ├── posts/              # `posts' pages directory
│   ├── index.html
│   ├── robots.txt
|   ├─- common-style.css
│   └── common-script.js
├── public/                 # target export directory
├── publish.el              # site sepecifc publishing config
└── Makefile                # for building the site outside of Emacs

只设定 org-publish-project-alist 就可以将项目结构解释给 ox-publish 以导出博客:

(setq org-publish-project-alist
        `(("pages"
           :base-directory "./src/"
           :base-extension "org"
           :recursive t
           :publishing-directory "./public/"
           :publishing-function org-html-publish-to-html)

          ("static"
           :base-directory "./src/"
           :base-extension "css\\|txt\\|jpg\\|gif\\|png\\|html"
           :recursive t
           :publishing-directory  "./public/"
           :publishing-function org-publish-attachment)

          ("fuloido.moe" :components ("pages" "static"))))

(org-publish-all t)

这里使用 ruby 预览网站, python 或者 node 也不赖 :

ruby -run -e httpd . -p 8000

使用 Github Workflow 持续部署

由于 Actions Market 上已经有了 Emacs 的 setup ,这里的 workflow 非常好配置。

steps:
  - name: Install Emacs
    uses: purcell/setup-emacs@master
    with:
      version: 30.1
  - name: Checkout
    uses: actions/checkout@v4
    with:
      submodules: recursive
      fetch-depth: 0
  - name: Setup Pages
    id: pages
    uses: actions/configure-pages@v5
  - name: Build with ox-publish
    run: |
      emacs \
      -Q --batch \
      -l publish.el \
      -f org-publish-all

  - name: Upload artifact
    uses: actions/upload-pages-artifact@v3
    with:
      path: ./public

构建速度意外的挺快。

Footnotes:

1

对于 ox-html 的导出选项,这篇是非常有帮助的 Org Manual 13.9 全解。

2

这个博客更详细的介绍了如何使用 ox-html 和 ox-publish。

Author: (email:[email protected])

Date: 2025-03-18 Tue 00:00