使用 Org-Mode 生成博客
Table of Contents
如今市面上博客程序繁多,各有优缺;在线笔记也是五花八门,都难以满足我的日常需求(尤其是对文章内代码编辑的方便)。Org Mode 自带了生成整站的本事,本站正是用此生成的一堆 HTML 文件,我是考虑到:
- 纯文本方便我管理和检索,以及用版本控制;
- 不想在服务器上安装一大堆环境;
- 平时个人文档、笔记都是用 Org Mode,市面上的默认都不支持,尤其是在线笔记;
- 对我写笔记和文章来说,更加灵活。灵活带来的问题当然就是麻烦,这不可否认,所以嫌麻烦的读者都可不必继续看了;这种麻烦却满足了我对灵活性的要求。
希望能帮助喜欢 Org Mode 的朋友。系统完整的 demo 代码已放到 GitHub:https://github.com/1u4nx/orgmode-blog-demo
1. 目录布局
要像写代码一样有一个清晰整洁的目录结构:
├── html/ ├── Makefile ├── Makefile.el ├── src/ ├── static/ └── templates/
- html 目录:最终生成的 HTML 文件全部存于此处,如果需要在 Web 服务器上部署博客,只需把此目录上传即可;
- Makefile 和 Makefile.el:Makefile.el 包含了生成 HTML 的代码及配置,为了方便用 make 命令,所以又再多出一个 Makefile;
- src 目录:所有用 Org Mode 写的笔记全部都放在这里;
- static 目录:博客会用到自定义的 CSS 样式,也许你还会用到 logo、JS,都统一放这里;
- templates 目录:注意看我博客,每页都有相同的顶部和底部,其实就是在生成每个 HTML 时自动将顶部和底部插入相关代码,我把顶部和底部代码独立成 HTML 文件放于此处。
2. Makefile.el
整套系统并不复杂,核心点就是 Makefile.el 中几段代码。
Org Mode 自带了一个叫 ox-publish 的发布框架,可以用它生成一个静态网站,只需要配置 org-publish-project-alist 变量即可,更加详细的流程可以参考官方文档:http://orgmode.org/worg/org-tutorials/org-publish-html-tutorial.html
完成源码+注释如下:
(require 'package) ;;; 后面需要加载三方库,所以先初始化包管理器 ;; (package-initialize) ;; (setq package-enable-at-startup nil) ;; 如果需要高亮代码 ;; (require 'htmlize) (require 'org) (require 'ox-html) (require 'ox-publish) ;; HTML模板目录 (defvar *site-template-directory* "templates") (defun read-html-template (template-file) (with-temp-buffer (insert-file-contents (concat *site-template-directory* "/" template-file)) (buffer-string))) (let ((org-publish-project-alist '(;; 配置 images 目录 ("images" :base-directory "src" ;; 生成时要拷贝这些扩展名的文件 :base-extension "jpg\\|png\\|c\\|gif" ;; 生成的目录 :publishing-directory "html" ;; 是否递归 :recursive t :publishing-function org-publish-attachment) ;; static 是网站静态文件的目录 ("static" :base-directory "static" :base-extension "jpg\\|png\\|c\\|gif\\|css\\|js" :publishing-directory "html/static" :recursive t :publishing-function org-publish-attachment) ;; src 是网站 org 文件目录 ("wiki-src" :base-directory "src" :base-extension "org" :publishing-directory "html" :recursive t ;; org-html-publish-to-html会把 org 转成 HTML 文件 :publishing-function org-html-publish-to-html :headline-levels 4) ;; 这个 rss.xml 目前是手动维护内容 ("rss.xml" :base-directory "src" :base-extension "xml" :publishing-directory "html" :publishing-function org-publish-attachment) ("wiki-project" :components ("wiki-src" "static" "rss.xml" "images")))) ;;; 设置 CSS 样式 (org-html-head-extra "<link rel=\"stylesheet\" type=\"text/css\" href=\"/static/css/default.css\" />") ;;; 取消默认的 CSS (org-html-head-include-default-style nil) ;;; 取消默认的 Javascript 代码 (org-html-head-include-scripts nil) ;;; XXX 用 org-html-head 可以设置 <head> 部分 (org-html-preamble (read-html-template "preamble.html")) (org-html-postamble (read-html-template "postamble.html"))) ;;; 设置 Mathjax 库的路径 (add-to-list 'org-html-mathjax-options '(path "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS_HTML")) ;;; 开始导出 (org-publish-project "wiki-project"))
为了方便,这些再写一个Makefile:
all: # 为了避免编码问题,先设置好编码 LANG=zh_EN.UTF-8 emacs --script Makefile.el clean: rm -rf html/* rm -rf ~/.org-timestamps/
3. 扩展功能
3.1. 站内搜索
可以考虑使用 Google 的站内搜索服务( https://cse.google.com/cse/all ),把代码贴到相关文件中,我是放在 index.org 中的,详细见 demo 代码中的 src/index.org。
3.2. 留言板
可用三方的留言服务,比如 Disqus、网易云跟贴等服务,然后把相关 JavaScript 代码贴到页面底部模板中(preamble.html)。
3.3. RSS
我是把博文和笔记混合在一起的,有时并不想把笔记出现在 RSS 中,所以 RSS 我是手动维护的 src/rss.xml。
4. 部署
4.1. 使用版本控制
通常可以把整套博客放到 GitHub 和 Bitbucket 中,它们都有免费的私有仓库。
4.2. 服务器部署
我只在服务器上安装了 Emacs 和 Nginx,安装 Emacs 是为了直接在服务器上生成 HTML。并从版本仓库中 clone 博客到某目录,再将 Web 服务器的目录指向 html 目录下。然后写了一个包含以下步骤的 update.sh 脚本:
进入项目目录 git pull 最新源文件 执行 make 命令
5. 我的发布流程
5.1. 本地预览
在博客项目目录中执行 make 命令,然后进入 html 目录,执行 Python 自带的 Web 服务:
$ python3 -m http.server
浏览器访问 127.0.0.1:8000。
5.2. 发布
我 commit 的粒度一般是一篇笔记提交一次,分章节的文章一口气无法写完的话,就是每完成一节就 commit 一次,然后在 commit 信息中写清楚。
每当准备更新线上博客时,本地执行:
$ ssh 服务器地址 update.sh
除此之外你也可以:
- 本地生成好 HTML 上传到服务器;
- 直接在服务器上写笔记(Emacs 可以远程编辑文件)
等等。