用DocPad构建静态网站

makefile + m4

最早用 makefile 管理站点,其中缘由可以参看用Makefile搭建博客,在不懂css的情况下硬生生用m4根据一个 WordPress 主题构建起了自己的站点。

评论系统采用第三方的 Disqus

Hakyll

几个月前因为觉得makefile + m4的方案不够灵活,打算换用现成的静态站点生成工具。出于对Haskell的着迷,我不由自主地选择了Hakyll,这次迁移站点内容没有发生任何变化,只是构建方式换成了 Hakyll。

DocPad

而今我正初窥网页开发门径,觉得Hakyll方案有不少缺点,其一是Haskell社区没有好用的HTML、CSS模板语言,而这一方面的佼佼者无疑是Node.js社区的一些方案如:JadeStylus。量外 Hakyll 文档极度匮乏,而且它重度依赖的arrow(比monad更一般化)这一抽象概念我理解不够深刻,使用起来捉襟见肘。

之前还犹豫过是否应该选择Ruby的解决方案,智能体开发中我接触了Slim,一些地方比Jade要灵活(标签属性不需要括号)。但在调研Jekyll和Octopress后发现结合Slim、Stylus困难不少,几经探索最终了解到Node.js社区的DocPad。在MDN浅尝了几篇介绍HTML、CSS的文章,阅读了朋友借我的几本Web设计书籍,打算start from scratch来实践所学知识。

Google Analytics

分析用。目前还不知道如何用它来创建一个页面widget显示访问最多的文章。

Disqus

评论系统。这次迁移把路径从/posts改成/blog了,通过上传一个url变化的csv文件让Disqus迁移。

Syntax highlighting

highlight.js

目前highlight.js还不支持C的语法高亮(尽管支持C++)。

相关文章

使用了docpad-plugin-related这个插件。

我在文章中一般写tags: haskell, algorithm而不是tags: [haskell, algorithm],这样它会根据tags字符串做完全匹配,而不是根据两篇文章tags有交集。所以我修改了下代码

1
2
if typeof tags is 'string'
tags = tags.split(',').map (s) -> s.trim()

让docpad-plugin-related把tags这个String split成数组。

上/下一篇文章

自己写了个小插件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module.exports = (BasePlugin) ->
class RelatedPlugin extends BasePlugin
name: 'around'

renderBefore: (opts,next) ->
documents = @docpad.getCollection 'posts'

prev = undefined
documents.forEach (doc) ->
if prev
doc.set prev: prev
prev.set next: doc
prev = doc

return next()

文章的layout里加上类似这样的代码:

1
2
3
4
if document.prev
span.prev
| Prev 
a(rel='prev', href=document.prev.get('url'))= document.prev.get('title')

分享按钮

Atom

写了个Ruby脚本产生Atomfeed,不知道Node.js有什么解决方案:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#!/usr/bin/env ruby
require 'hpricot'
require 'rss/maker'

content = RSS::Maker.make('atom') do |m|
m.channel.title = 'MaskRay'
m.channel.link = 'http://maskray.me/atom.xml'
m.channel.description = 'MaskRay'
m.channel.author = 'MaskRay'
m.channel.updated = Time.now
m.channel.id = m.channel.updated.to_s
m.items.do_sort = true

Dir['out/blog/*.html'].sort.reverse[0..5].each do |f|
doc = Hpricot open(f).read
i = m.items.new_item
i.title = (doc/'title').inner_text.sub 'MaskRay | ', ''
i.link = "http://maskray.me/#{f[4..-1]}"
i.date = Time.parse((doc/'time')[0].inner_text)
i.description = (doc/'#post-content').inner_text
end
end

File.open('out/atom.xml', 'w') do |f|
f.write(content)
end

去掉url中的.html后缀

Apache的.htaccess文件里加上:

RewriteEngine on
RewriteBase /

RewriteRule ^posts/(.*)(\.html)?$ /blog/$1 [L,R=301]

我的另一些奇怪要求,把浏览器的带.html后缀的url重定向到不带.html后缀的url。这个任务比想象中难很多,原因在于我不知道如何处理浏览器和本地解析地址不同的问题。这个问题得到了fqj1994同学的大力帮助,也耽误了他好多时间。

RewriteCond %{REQUEST_FILENAME}/ -d
RewriteCond %{REQUEST_FILENAME}.html !-f
RewriteRule [^/] - [L]

RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.*)\.html$ /$1 [R=301,L]

RewriteCond %{REQUEST_FILENAME}.html -f
RewriteRule [^/]$ %{REQUEST_URI}.html [QSA,L]