最开始使用 GitBook 撰写电子书是从去年开始维护的 billryan/algorithm-exercise 算法文档开始的,因为这个项目我已经造了不少轮子,给 GitBook 添加类似博客中的 category/tag 功能的插件在下班后的周末抽空写了写,趁这个中秋小长假美化了 CSS, 修了修 bug. 下文先介绍如何使用 gitbook-plugin-tags 插件,随后介绍自己实现这个插件的全过程。

使用

预览网站 ==> https://yuanbin.gitbooks.io/test/content/

根目录下手动新建tags.md

由于 GitBook 在 2.0.0 之后就将 summary 的 hook 移除了,所以目前需要先在根目录下新建 tags.md 文档并将其置于 SUMMARY.md 的最末尾。以某文件夹为例:

1
2
3
4
5
6
7
8
en
├── README.md
├── SUMMARY.md
├── faq
│   ├── README.md
│   ├── contributors.md
│   └── guidelines_for_contributing.md
└── tags.md

其中 SUMMARY.md 的内容如下:

1
2
3
4
5
6
7
# Summary
* [Preface](README.md)
* [FAQ](faq/README.md)
* [Guidelines for Contributing](faq/guidelines_for_contributing.md)
* [Contributors](faq/contributors.md)
* [Tags](tags.md)

切记* [Tags](tags.md)务必位于 SUMMARY.md 的末尾,因为 GitBook 是按顺序解析渲染的。

tags.md 中的内容自定,比如可以只包含一行 # Tags 作为标题。

新增 tags

tags 标记可以使用 YAML 在 markdown 源文件的前导处加入,如

1
2
3
4
5
---
tags: ['tag1', 'tag2', 'tag3 is here']
---
# FAQ - Frequently Asked Question
...

也可在正文中以单独一行表示,tag 之间以逗号分隔,tags 一定要在一行的开头,否则不予解析。

1
2
3
# FAQ - Frequently Asked Question
tags: tag1, tag2, tag3 is here

在正文中出现的 tag 格式要求相对较为随意,最关键的是一行开头要有 tags:, 不同 tag 以逗号分隔。

book.json 中新增 tags 插件

plugins 内增加 tags 即可,无需其他配置。

1
2
3
4
5
6
{
"plugins": [
"...",
"tags"
]
}

实现

功能设计

受 Hexo 博客引擎启发,tags 应该单独有一页面,该页面包含各 tag 所在的原网页链接,原网页链接则包含指向 tags.html 的链接,页面内容较多时需要使用定位符直接跳转到指定位置。简化起见,这里不为每个 tag 生成新页面,而是所有 tag 在一个 tags.html 页面中显示,利用 # 定位不同标签名。综合下来有两大基本需求:

  1. 源文档中的 tags: 处应能指向 tags.html 的链接,并根据不同 tag 以 # 加速定位
  2. tags.html 中应能包含不同 tag 所指向的原网页链接。

除了以上两个基本需求外,此插件最好能支持多国语言,同时用户设置 tag 信息时应比较人性化,显示 tag 最好能美观大方一些,而不是纯文字链接,俗话来说就是要讲究用户体验。

生成 tags.html

由于 GitBook 是从 SUMMARY.md 中提取 markdown 进行解析渲染的,所以在没找到直接调用解析生成 tags.html 的方法之前还是需要用户在根目录下新建 tags.md 并将其置于 SUMMARY.md 末尾,这样我们就能充分利用 GitBook 解析生成 tags.html 了。如果不在 SUMMARY.md 中添加 tags.md, 那么我们要么能在 GitBook 读取 summary 之前用程序加进去,要么能直接渲染生成 tags.html 静态文件。summary 的 hook 在 2.0.0 之后便被移除,直接渲染的方法一时也没有看到,所以折中下来暂时只能先麻烦下用户了。

CSS 美化

自己不是专业的设计师,所以参考了 https://hexo.io 和自己博客的主题,结合了 fontawesome 字体,取消了逗号分隔,为每个 tag 加了边框等等细节,看起来总算是舒服了一点点。由于在 markdown 中添加 div 标签等信息不太方便,这里我用了预加入 <!-- tags --> 信息以方便后期 HTML 中添加 tags 等 id 和 class.

多国语言

与 sitemap 插件不同,该插件多国语言的支持在于巧妙利用了浏览器和 markdown 解析器的寻址方式,用户浏览时会自动补全前面的网址等信息。

定位符直接定位

借助 github-slugid, 我们可以很方便的在 GitBook 中根据不同 header 生成相应的定位符。

正则匹配

之前正则匹配用的不熟,这次发现 JavaScript 中字符串的操作用正则实现十分便利,尤其是 /im 的引入可使得每一行单独处理而不是一次处理整个 page.content.

如果你喜欢我这个插件,不妨给这个项目 billryan/gitbook-plugin-tags 加一颗星吧 :)

Comment and share

Gitbook 用于写大型文档尤其是有层次关系的书籍类电子书还是挺合适的,但其默认的 CSS 对中文并不太友好首先匹配英文字体族,fallback 至sans-serif 字体族,这在中英文和简繁并用时会有一些小小的问题。好在 Gitbook 提供了自定义 website/ebook 等 CSS 的方法 ==> How can I include custom CSS? · GitBook

这里我们主要关注网页版的阅读体验,所以在 styles 目录下新建 website.css 即可,默认的主题 GitbookIO/theme-default 关于 font-family 的设置为

1
2
3
font-family: @font-family-base;
@font-family-sans: "Helvetica Neue", Helvetica, Arial, sans-serif;
@font-family-base: @font-family-sans;

为了能在 website.css 中覆盖默认样式,我们需要使用更高的权重,这里我使用了 .book.book-summary .book-body 三个类提升权重。具体可参考:

以简体中文的样式为例,使用了简体字型在前,繁体在后的方式适配。

1
2
3
.book .book-summary, .book .book-body {
font-family: "Microsoft YaHei UI", "Microsoft Yahei", "PingFang SC", "Lantinghei SC", "Hiragino Sans GB", "WenQuanYi Micro Hei", "WenQuanYi Zen Hei", "Noto Sans CJK SC", "Microsoft JhengHei UI", "Microsoft JhengHei", "PingFang TC", "Lantinghei TC", "Noto Sans CJK TC", "Helvetica Neue", Helvetica, Arial, sans-serif;
}

Comment and share

博客托管在 GitHub 的话,默认的 *.github.io 是启用 HTTPS 的,但如果是自定义域名的话就没这么方便了。如今虽然有 Letsencrypt 这种工具,但 GitHub Pages 这种高度依赖 CDN 服务的产品要想给自定义域名支持 HTTPS 估计还得一些时日。

第三方能支持 HTTPS 的有 CloudFlare 和 Kloudsec, 如果不是 CloudFlare 的合作厂商,得将 NS 记录转接,想了想 DNSPod 还是不错的,遂转向了 Kloudsec. Kloudsec 足够方便,只需要改下 DNS 记录基本就好了,谁知没用多久七月九日就收到一封『Kloudsec is shutting down』的邮件,不得不感慨这年头免费好用的午餐确实不长久。

由于自己有 VPS,一直在想办法将 blog 托管在自己网站上,结合 Letsencrypt 支持 HTTPS 还是不难的。最开始的思路是用 travis 推送静态文件到 VPS,现在想想这种思路还是有点复杂的。其实结合 hexo 的 deploy 插件,除了 git 之外还可以通过 rsync, heroku 等方式发布。

dokku

之前一直听说过 dokku 作为 PaaS 的方便之处,基于 docker 使得 dokku 几乎可以作为 heroku 的开源替代。周五和茄子/大鹏回学校时聊到了用 dokku 部署博客,由于 dokku 兼容 heroku 的那一套应用发布机制,所以可以直接使用 hexo 的 heroku deploy 插件发布到 dokku! 我使用的 DigitalOcean 有 dokku 的 instance 可以选择,因此安装过程就免去了。这里需要注意的是5刀一个月的内存只有 512 MB, 比 dokku 推荐的 1G 还是要小不少的,解决办法就是利用 swapfile, 详细过程见 How To Add Swap on Ubuntu 14.04

安装

dokku 的安装可参考 官方指引

安装好 dokku 之后一般还需要添加发布用的用户,按照 User Management 中的步骤操作即可,0.7 起可以使用

1
cat ~/.ssh/id_rsa.pub | ssh dokku@dokku.me ssh-keys:add KEY_NAME

方式添加,不再需要 sshcommand. 其中 KEY_NAME 只是用于标记用的名字,可以不是用户名。如果远程服务器的 ssh 端口不是 21,建议在 ~/.ssh/config 中添加如下行

1
2
3
Host your_domain.com
HostName your_domain.com
Port your_port

部署

和 heroku 不一样的是,由于 dokku 往往是部署在自己 VPS 中,所以需要先在自己 VPS 上进行 dokku apps:create blog 添加好之后进入自己的 hexo blog 目录,在 _config.yml 的 Deployment 段添加

1
2
3
4
5
6
7
# Deployment
## Docs: http://hexo.io/docs/deployment.html
deploy:
- type: git
repo: git@github.com:billryan/blog.git,gh-pages
- type: heroku
repo: dokku@your_domain.com:blog

完全不用 GitHub Pages 的可以将 git 的那一段去掉,安装 heroku deploy 插件

1
npm install hexo-deployer-heroku --save

发布时 hexo deploy --generate 遇到 Another gzip: stdin: not in gzip format 错误的需要手动更新 gliderlabs/herokuish 镜像。

启用 HTTPS

Step1: 安装插件 dokku/dokku-letsencrypt

1
sudo dokku plugin:install https://github.com/dokku/dokku-letsencrypt.git

Step2: 为 blog 应用配置证书需要用到的邮箱

1
dokku config:set --no-restart myapp DOKKU_LETSENCRYPT_EMAIL=your@email.tld

Step3: 生成证书

1
dokku letsencrypt blog

生成证书前记得将 blog DNS 解析到你的 VPS。

Step4: 自动更新证书

1
dokku letsencrypt:cron-job --add

由于使用 Letsencrypt 生成的证书是有有效期的,所以还需要配置自动更新证书。

Comment and share

Yuan Bin

Quality Matters
http://www.yuanbin.me


Software Developer


China, Shanghai