2018年8月31日星期五

把我的个人网站推倒重来(Part 1 - 用 Harp 做模板引擎)

根据模板和数据生成静态网站的框架有很多,例如说 HarpJekyllHugo 等等。我对比了一下,最终选择了用 Harp,因为它是用 JavaScript 写的,如果我真的需要做什么改动我可以轻易地去改它的源代码。用 Harp 的坏处也很明显,这个项目在 GitHub 的源代码上已经很久没更新,搞不好将来不再有人维护。

安装 Harp 和用 Harp 编译生成静态页面很容易。因为 Harp 是「convention over configuration」的框架,所以每个页面在使用数据时会优先在里自己目录里的 _data.json 文件,然后看项目根目录里的 harp.json。然而有一个问题是 Harp 没解决的:本地化(多国语言文字)。

本地化

我用每种语言一个目录的方式解决本地化问题:

public/
  ├ _data.json
  ├ index.jade
  ├ _partials/
  │   ├ index.jade
  │   └ resume.jade
  ├ en/
  │   ├ _data.json
  │   ├ index.jade
  │   └ resume.jade
  └ zh/
      ├ _data.json
      ├ index.jade
      └ resume.jade

无论是哪个语言的 index.jade,调用的代码都是 public/_partials/index.jade,只不过把自己当前所拥有的 _data 传过去。无论是哪个语言的哪个文件,都调用 public/_partials/ 下的同名文件,因此所有这些特定语言特定文件都只有一行相同的代码

至于背后实际干活的那个 public/_partials/ 下的文件,它需要同时看 public/_data.jsonpublic/{locale}/_data.json 来进行渲染:前者为它提供语言无关的数据,后者为它提供语言相关的数据。

一开始的时候我严格执行 public/_data.json 只放语言无关数据,后来我发现这样编辑起来很麻烦,因为一个模板往往同时涉及两种数据,我需要修改两个 _data.json 文件。于是我把英文数据和语言无关数据都放到了 public/_data.json 里面,写文档时专注于写英文版。英文版完成后再翻译为其他语言,这时候 public/{locale}/_data.json 里的翻译就会覆盖 public/_data.json 中的同名数据,语言无关的数据自然不会被覆盖。

为了实现「覆盖」这一项功能,我还专门实现了一个 deepCopy 函数用来深复制 JSON 数据。我希望 Harp 能够内置这个功能:_data.json 从文件所在目录开始层层往上覆盖,一直覆盖到 harp.json 为止。在 Harp 支持这个功能之前,我只能自己先实现一个版本来方便我做本地化。

调试技巧

有时候我们实在想看一下 Harp 可访问的数据结构。我们知道 public 对象是任何页面都能访问的,public/ 目录下每一个子目录都会产生一个同名子对象,每一个文件的文件名会以字符串形式出现在对应子目录对象的 _content 中,每一个 _data.json 文件的内容都会展开在对应子目录对象的 _data 中。说这么多,还不如直接把整个 public 打印出来看看!

为此我专门做了一个 debug.jade 的 partial,需要打印 Harp 运行时变量的话就调用一下 != partial('debug', { data: public }),变量立即从 JavaScript 中打印出来。(其中 public 可以被替换为任何我想要查看的变量。)

关于 Harp 的部分到此结束,虽然我还没有把所有改重写的页面都写完,但我觉得 Harp 应用上的问题都已经解决完了。在下一篇文章里,我开始要解决页面布局问题了,如果你喜欢跟着我一起折腾的话,欢迎通过邮件RSS/Atom 订阅我的博客。

2018年8月24日星期五

把我的个人网站推倒重来(Part 0 - 历史背景)

我的个人网站最初是架设在 catchen.biz 上面的,当时还在大学里,只是想做个网站存放简历和作品,方便找工作。那个时候我还自己设计了这个网站的模板,然后用上了时下最流行的 XHTML + CSS + JavaScript 来实现这个模板。每个页面顶部都有一行在 HTML5 时代早已不需要的声明:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

这么多年过去了,我只更新过上面的简历信息,模板没有重新设计过,实现也没有更新。这造成了很多问题,也给我这次的推倒重来留下了很多可以做的事情:

  1. 不支持 responsive design,在移动浏览器上难以使用。Google 直接发邮件来通知说,不为移动浏览器优化的页面会在搜索结果里面降权。如果支持 AMP 的话,可能能在 Google 搜索结果和移动浏览器中获得更好的体验。
  2. 不支持 HTTPS。当年搞个 HTTPS 证书很麻烦,而且 SNI 尚未流行所以还需要跟服务运营商要求独立 IP,现在这一切都变得很简单。
  3. 缺乏页面模板,每个页面的源代码都需要手工维护。现在静态网站引擎那么多,这个问题可以轻易解决掉。
  4. FTP 上传麻烦,必须覆盖所有文件。这样的部署方式太不方便,我还是需要为此而保留一个 FTP 客户端。因为不知道哪些文件更新了,所以每次都必须要上传并覆盖所有文件。

为了解决这些问题,我选择了把整个网站推倒重来。在这个过程中,我顺便把网站迁移到 catchen.me。这样子我就可以在 catchen.me 上慢慢折腾我的半成品,同时保持 catchen.biz 正常运作。完工后,我只需要在 catchen.biz 上用 301 转跳指向 catchen.me 即可。

在下一篇文章里,我就要开始讲述我如何折腾我的个人网站了,如果你喜欢跟着我一起折腾的话,欢迎通过邮件RSS/Atom 订阅我的博客。

2018年8月21日星期二

《The Dictator's Handbook》摘要

这次试试新玩法:在读数过程中把想到的直接发往 Twitter,然后再把所有的 tweets 加到一个 moment 里面,最后把 moment 嵌入到博客当中。这次读的书是《The Dictator’s Handbook: Why Bad Behavior is Almost Always Good Politics》,摘要请看下面嵌入的 tweets。

P.S. 嵌入 tweets 的坏处是对 SEO 不利,因为所有 tweet 的内容都没有出现在页面的 HTML 里面。此外这样做也可能影响 Feed 和邮件阅读的体验,不过我总要试一次才知道体验如何嘛。