用 Org-Mode 与 GithubPages 搭建个人博客
如果你已经熟练使用 Emacs Org-Mode 并且也对 github 有所了解,那么在 Github Pages 上 搭建一个博客将是十分简单的事情。你 不需要 装诸如 Ruby、Jekyll 之类的软件,就可 以用 Org-Mode 写博客然后发表到 Gitub Pages 上。
在 GithubPages 上创建博客
你只需照着 https://pages.github.com/ 几步就可以创建一个自己的博客。请注意,这其 实就已经是一个“能工作”的博客了!“能工作”的意思是你往里添加的html页面都可见了。
当然,作为一个博客,仅仅能显示我们自己添加的页面还差了点。至少每次发表一个文章
之后,它应当能自动显示在博客首页而不需我们自己编辑 index.el
。这就需要用到
Jekyll 了。
配置 Jekyll
导入 Jekyll 框架
虽然我们需要用到 Jekyll,但我们 不用 在本机安装相关软件。相关处理都是在 Github Pages 服务器端运行的。我们要做的只是导入 Jekyll 框架并按照 Jekyll 的规则 命名以及编辑文件(准确的说,我们用的是 Jekyll-Bootstrap)。如下克隆一个 Jekyll-Bootstrap 的模板然后把它 push 到自己的博客上(以下以我的博客为例)。
git clone --depth 1 https://github.com/plusjade/jekyll-bootstrap.git blog git remote set-url origin https://lgfang@github.com/lgfang/lgfang.github.io.git git push -f
刷新博客页面应当可以看到博客内容已经变了。
更改配置
(详情参见博客源码)
- 修改 _config.yml 填入自己的 google tracking id 和 disqus 账号等个人信息。
前者是让google帮你统计页面访问情况的,后者是一个第三方评论系统。相信用法后面 org-mode 配置时会提到。
- 更改 README.md 中的描述
- 修改 index.md 成显示最近五篇博客的摘要。
- 重定向 404 页面到寻找丢失儿童的页面。
- 把主题改成 twitter 的。
cd _layouts sed -i 's/bootstrap-3/twitter/g' *html
NOTE: 可用的主题在 _includes/themes 下。
- 添加更多的 css 和 js
把 Org-Mode publish html 用到的 css 和 javascript 也加入到博客中。因为后面 将要提到的“笔记”的缘故,我把这些文件放到
mynotes/cssjs
目录下,并且编 辑_includes/themes/twitter/default.html 加入对 css 的引用:$ git diff diff --git a/_includes/themes/twitter/default.html b/_includes/themes/twitter/default.html index 3747764..01ba331 100644 --- a/_includes/themes/twitter/default.html +++ b/_includes/themes/twitter/default.html @@ -17,6 +17,7 @@ <!-- Le styles --> <link href="/bootstrap/css/bootstrap.2.2.2.min.css" rel="stylesheet"> <link href="/css/style.css?body=1" rel="stylesheet" type="text/css" media="all"> + <link href="/mynotes/cssjs/tango.css" rel="stylesheet" type="text/css" media="all"> <!-- Le fav and touch icons --> <!-- Update these with your own images
我的模板
至此 Jekyll 端的配置就基本完成了。为了方便起见我创建了一个名为“blog-template” 的 branch ;所有博客设置的改动都在这 branch 上。你图省事的话也可以直接克隆我现 成的模板。
愿意的话现在就可以用 markdown 的语法来写博客并按 yyyy-mm-dd-blog-title.md 的 格式放到 _posts 目录下就可以发表了。但是,作为资深 Org-Mode 用户:) 这显然不是 我的目的。用 Org-Mode 写博客不仅仅是免去了学习 markdown 的语法,更重要的是可 以利用 Org-Mode 的各种强大功能。
经验教训
- 一定要验证自己的每一步 Jekyll 改动都对,因为 debug 不方便。
- 检查自己注册时的邮箱,错误信息会发到此处。
我在此次配置过程犯了一个小错误,结果花了几乎一晚上来 debug :我试图在 categories.html 里包含一个我手工创建的 html 文件,但是文件名写错了。结果是 push 了新的博文,博客也不更新。应该是 Jekyll 处理失败就退出,导致整个博客始终 停留在错误被引入之前的状态。
配置 Org-Mode for blog
org-mode 需要做如下配置:
- 创建两个工程(project)。
- 一个用于发布博文,即把 Org-Mode 的原文转成 html
- 结果文件必须放到 _posts 下。
- 只导出 body, 因为我们需要 Jekyll 来帮我们生成 head 。
- 导出的 link 要用绝对路径,这主要为了链接图片方便。Jekyll 处理之后,博客 的 url 里会带上日期;而我本地的博文和图片等附件没有按日期创建目录(又烦 又不方便将来查看);所以最简单的办法就是把图片全放到固定的目录,然后在博 文里用绝对路径指向它们。
- 一个用于发布附件(图片之类的)
如前所述,图片不能直接放到 _posts 下。创建一个和 _posts 平级的目录 images, 把附件都放到这。
(setq ;; nil as default to avoid leaking sensitive info unintentionally, ;; overwritten in per-project settings bellow org-html-postamble nil org-publish-project-alist '( ("blog-attachments" :base-directory "~/myblog" :base-extension "png\\|jpg" :recursive t :publishing-directory "~/websites/blog/images" :publishing-function org-publish-attachment) ("blog" :base-directory "~/myblog" :base-extension "org" :recursive t :publishing-directory "~/websites/blog/_posts" :publishing-function org-html-publish-to-html :auto-sitemap nil :body-only t ;; Only export section between <body> </body> :html-link-use-abs-url t )) org-export-allow-bind-keywords t ; I like "#+BIND:var value" )
- 一个用于发布博文,即把 Org-Mode 的原文转成 html
- 创建 yasnippet 模板
每篇博文的开头都要加上所谓的 front matter 才能够被 Jekyll 识别处理。老老实实 每次手工输入绝对不是 emacs 老鸟干的事。我定义了一个名为
new-blg
的 yasnippet 模板(NOTE: 为了和 yasnippet 自带的 "blog" 模板区分,我的模板名省略 了字母"o")。每次输入它就可以自动展开成所需的 front matter。具体代码如下:# -*- mode: snippet -*- # name: new-blg # -- # -*-mode:org;coding:utf-8-*- # Created: `(format "%s %s" (user-full-name) (format-time-string "%m/%d/%Y"))` # Modified`(format ": %s %s" (user-full-name) (format-time-string "%m/%d/%Y %H:%M>"))` #+OPTIONS: toc:nil num:nil #+BIND: org-html-link-home "`(replace-regexp-in-string "/Users/lgfang/myblog" "http://lgfang.github.io/images" default-directory t t)`" #+TITLE: ${1:title} #+BEGIN_HTML --- layout: post title: $1 tagline: categories: ${2:computer} tags: [${3:emacs}] --- #+END_HTML $0
配置 Org-Mode for Notes
我主页上除了博文外,还有一些经年积累下来的笔记和演讲稿(什么该算做博文,什么该 算做笔记?我也很迷糊,谁有建议请留言,谢!)。对于这些资料,Org-Mode publish 出 来的效果更适合我的需求:可以做为幻灯片播放,可以快速跳转。因此,为它们定义了两 个和之前设置略有不同的 project。因为这些页面是原封不动发布到网站上,所以google analytic 和 disqus 的代码我们必须自己通过设置 postamble 来加上(请注意我把个人 信息存在变量中)。
(setq org-publish-project-alist '( ;; ... ("notes-attachments" :base-directory "~/mynotes" :base-extension "css\\|js\\|png\\|jpg\\|patch" :recursive t :publishing-directory "~/websites/blog/mynotes" :publishing-function org-publish-attachment) ("notes" :base-directory "~/mynotes" :base-extension "org" :recursive t :publishing-directory "~/websites/blog/mynotes" :publishing-function org-html-publish-to-html :exclude "\\(todo\\|confidential\\)" :html-postamble get-public-postamble :auto-sitemap t :sitemap-filename "notes_list.org" :sitemap-title "List of lgfang's notes" :sitemap-style tree :sitemap-sort-files anti-chronologically :sitemap-sort-folders last :sitemap-file-entry-format "%t") ;; ... )) (defun get-public-postamble (plist) (let ((title (plist-get plist :title)) (creator (plist-get plist :creator)) (time (format-time-string org-html-metadata-timestamp-format))) (format " <br/> <p> <span class=\"date\">Created: %s</span> by <span class=\"creator\">%s</span> </p> <!-- DISQUS --> <div id=\"disqus_thread\"></div> <script type=\"text/javascript\"> /* * * CONFIGURATION VARIABLES: EDIT BEFORE PASTING INTO YOUR WEBPAGE * * */ var disqus_shortname = '%s'; // required: replace example with your forum shortname /* * * DON'T EDIT BELOW THIS LINE * * */ (function() { var dsq = document.createElement('script'); dsq.type = 'text/javascript'; dsq.async = true; dsq.src = '//' + disqus_shortname + '.disqus.com/embed.js'; (document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(dsq); })(); </script> <noscript>Please enable JavaScript to view the <a href=\"http://disqus.com/?ref_noscript\">comments powered by Disqus.</a></noscript> <a href=\"http://disqus.com\" class=\"dsq-brlink\">comments powered by <span class=\"logo-disqus\">Disqus</span></a> <!-- google analytic --> <script> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); ga('create', '%s', 'auto'); ga('send', 'pageview'); </script> " time creator ;; The following variables are defined in private-info.el disqus_shortname google_analytic_track_id_blog)))
# -*- mode: snippet -*- # name: new-notes # -- # -*-mode:org;coding:utf-8-*- # Created: `(format "%s %s" (user-full-name) (format-time-string "%m/%d/%Y"))` # Modified`(format ": %s %s" (user-full-name) (format-time-string "%m/%d/%Y %H:%M>"))` #+HTML_HEAD: <link rel="stylesheet" type="text/css" href="../cssjs/lgfang.css" /> #+INFOJS_OPT: toc:t tdepth:2 ltoc:nil view:showall path:../cssjs/org-info.js up:../index.html home:../../index.html #+OPTIONS: num:t #+TITLE: ${1:title} * ${2:header1} $0
blog comments powered by Disqus