现在你来到了Ghost的世界(或别的什么本地博客系统),怎么写博客以及格式等等问题都是这个博客系统的问题了,你应该去搜搜相关的教程。就我来说,Ghost挺好用的,偶尔还有些很便利使用的小惊喜。
如果你成功的导入了历史博客(或者你只是随手写了几篇),那么现在你面临的问题是:怎么把它放到网上去。当然可以是某个免费主页空间(只需要静态的就可以了),也可以是——比如我选择的就是Github Pages。这样一来,就可以有一个名为xxxxxx.github.io
的博客地址了,而且博客文章和维护等等都使用Github的后台或Git命令行,又熟悉又自然,对吧。
4. Github开工
你得先有Github账号。然后,创建一个名为xxxxxx.github.io
的仓库。最后,你进入这个仓库,在仓库的Settings(注意不是你的帐户的Settings)中找到GitHub Pages
,检查一下,他可能已经缺省写着:
Your site is published at https://xxxxxx.github.io/
OK。建议你将Features中的Wikis
与Restrict editing to collaborators only
设为关闭,而Issues
建议开启——我相信你用得到它。
最后,你还可以在Theme chooser
中选一个Theme。不过对我来说没什么意义,因为我将使用Ghost中的Theme。不过,如果你使用了Github的Theme,那么你的主页根目录——也就是xxxxxx.github.io
这个仓库的根目录下就会多一个_config.yml
文件。
此外,还总是会有一个README.md
文件,知道Github的人都知道这个文件用来做什么,建议你留着——尽管删除掉也没什么影响。
除了上述两个文件,Github什么都没给你,一切都得自己来干。
当然,只要你创建了这个仓库,那么https://xxxxxx.github.io
就已经可以访问了;如果你更新这个仓库,那么网站也就自动更新了。
很酷。
5. 从本地博客到Github Pages
尽管几乎所有的Ghost用户都被推荐使用Buster来生成静态页(generate static pages),但这个工具确实相当不好用,按某博主所说『是个大坑』,不过我也建议你看看他的博客文章(在这里),写得很细致了。不过如果你不怎么用Python的话,我建议你不要安装pyenv和多版本的python,直接用MacOSX原装的就好——或者只用Brew安装Python 2.x。
参考上面这位博主(Kris Cotter)的文章,我写了一个名为makesite.sh
的脚本,它配合Buster使用,并主要用来填Buster的一些坑。下面说说这个工具。
5.1 使用makesite.sh的标准过程
参考下面的控制台命令:
## 取一份你的Github Pages仓库,例如(YOURNAME/YOURNAME.github.io)
> git clone https://github.com/YOURNAME/YOURNAME.github.io
> cd ./YOURNAME.github.io
## 定制一下git exclude files
> echo -e '\nstatic/\nmakesite.sh\npatchme.sh\nbuster.log’ >> .git/info/exclude
## 下载makesite.sh文件到本地仓库
> wget -nv 'https://github.com/aimingoo/ghost-utils/raw/master/makesite.sh'
## 使用帮助
> bash makesite.sh --help
###########################################################################
Usage:
> bash makesite.sh --generate --reset-domain --short-path --deploy-now
...
上面列举了makesite.sh对Ghost -> Github Pages
的一个标准过程的理解,亦即是分成四步:
- generate: 调用Buster生成静态页
- reset-domain: 重置本地博客的domain到远端(YOURNAME.github.io)
- short-path: 生成简短的网页路径
- deploy-now: 部署到Github仓库
你可以使用参数来开启或关闭任何一个步骤,或者从任何一个步骤开始(而无视于其它步骤)。缺省情况下所有的步骤都是关闭的,只检查一下当前目录下是否存在./static
子目录。——注意这个目录是被保留,不被提交到Github仓库中去的(所以前面的脚本中我将它添加到了.git/info/exclude
文件中)。
整个过程需要依赖git
和buster
两个工具,另外需要wget
、grep
和MacOSX版本的sed
。如果你是在别的系统上运行这个脚本,你"可能"需要改一下sed的命令行参数。
如果你只是生成静态页而不部署它,那么你不需要使用--deploy-now
参数,这种情况下没有安装git也是可以的。但我总是建议你先安装buster:
## 使用Python的PIP安装buster
> pip install buster
## 如果你没有wget或git
> brew install wget git
5.2 makesite.sh的配置与参数
如果你读makesite.sh的源代码,你会发现它处理参数的代码非常漂亮(嘿~嘿~)。
这些参数可以有两种格式:
-
--reset-domain=false
:指定reset-domain参数值为false。 -
--reset-domain
:这种省略掉值的情况,等效于--reset-domain=true
。
也可以指定字符串值,例如设置你的domain(缺省值是我的"aimingoo.github.io"):
--domain='YOURNAME.github.io'
所有通过命令行参数传入的参数配置,都有相对应的bash变量(全大写字符),所以你也可以直接修改.sh脚本中的变量缺省值,以避免每次都要通过命令行指定(例如,尤其是--domain
和--generate-info
这样的参数)。
由于通常你都需要配置自己的domain参数,所以我没有将makesite.sh写成通用脚本,而是建议你每个Github本地仓库下载一份独立的,并修改其中DOMAIN变量的缺省值。
也正是因此,它也被加入了git的排除文件列表。
6. 填了哪些坑?
前面说过makesite.sh用来填Buster的一些坑的。但填了哪些坑呢?下面讲讲技术问题。
6.1 Buster调用wget时的参数问题
6.1.1 Buster其实只帮你抓5页Pages
如果你的博客很多,有很多的分页(比如我的就有五十多页),那么你很容易就发现其实Buster只帮你抓了其中的5页——很郁闷吧。
这是因为Buster调用wget来抓取页面,而它在递归下载时默认搜索的递归尝试就是5层,这个需要修改--level
参数。
6.1.2 你可能需要忽略掉一些抓取页面
Ghost默认会帮你生成很多东西,有SEO用的amp文件、sitemap文件或rss文件,又例如最新的ld+json数据。然而你不见得都需要用到,其中最严重的就是amp,因为这相当于你生成了两份博客,所以我们需要用--reject-regex
来忽略掉它。
还有一种情况非常特殊。在Ghost博客里,tag页可能有两种url(事实上所有的页面都会有这两种页):/tags/XXX
和tags/XXX/
。别小看多出来的这个斜杠/
:当wget访问/XXX
页时,它是将url理解为文件的,因此将要写入的是文件XXX(如果加上--adjust-extension
参数那么就写入XXX.html);而访问/XXX/
时,wget认为它访问的是目录,所以也就会尝试创建XXX这个目录并写入./XXX/index.html
。
然而我们设想一个问题:如果一个网站中既有/tags/XXX
又有tags/XXX/
,那么当wget先找到前者的时候,就会在当前目录下写一个XXX文件,而下一次它找到后一种的时候,会发生什么呢?
这有三种可能性:
- 如果有XXX目录,而又要创建XXX文件的话,wget会创建一个名为XXX.1的文件;
- 如果反过来是有XXX文件的情况下,
- 需要再创建./XXX/目录,那么wget直接覆盖XXX文件,于是旧的XXX文件丢失,多出来一个新的XXX目录;
- 需要创建
./XXX/yyy/index.html
这样的子级目录中的文件的话,那么很不幸,wget抛出一个异常./XXX/yyy : Not a directory
,写文件不成功。
所以,我们需要忽略掉一些抓取页面,因为他们可能先于一个目录创建之前要写入,又或者与已写入的文件冲突,再或者根本就是多余的、重复的页。
6.1.3 不修改buster.py的做法
为了不修改Buster的源代码,我在makesite.sh中定义了一个名为wget的函数,并且在当前进程中导出它。这样一来,由于Buster是由makesite.sh这个shell脚本launch起来的,那么当它调用wget下载的时候,就调用了我们在程序中修改过的版本。
——这是一种在当前脚本中打patch的方法(可以不修改buster.py的源代码)。基本的代码如下:
##
## 参见makesite.sh源代码
##
## 声明函数并追加参数
function wget { $RAW_WGET --level=0 inf --reject-regex=... }
## 取原始的wget的路径并导出到当前环境中
export RAW_WGET=`which wget`
## 将wget函数导出到当前环境中
export -f wget
## 调用buster,这时buster将使用我们在代码中声明的wget函数来下载
buster ...
6.2 移除版本号
在新近一些的前端技巧中,为JavaScript和CSS文件加上版本号已经是很流行的做法了。然而这意味着Buster抓取的文件会存成类似shared/ghost-url.js?v=3edb33f1b1
这样的名字。
所以在makesite.sh中有两行代码来对assets
和shared
目录中的资源做更名,以移除这种版本号:
## 移除assets目录中的资源版本号
> find static/assets -name '*\?*' -type f -exec sh -c "echo '{}' | sed 's|\?.*$||' | xargs -I[] mv '{}' '[]'" \;
## 移除shared目录中的资源版本号(通常只有/ghost-url.js这个文件)
> find static/shared -name '*\?*' -type f -exec sh -c "echo '{}' | sed 's|\?.*$||' | xargs -I[] mv '{}' '[]'" \;
6.3 从reset-domain到short-path
reset-domain是Kris Cotter最早版本代码中的功能,简单地说就是将Buster下载的网页文件中残留的localhost:2368
再做一次替换,所以我将这个过程叫做reset-domain。
事实上wget的--convert-links
参数做过一次高性能的链接转换,但这远远不够——这些转换基于wget的html parser中对"链接"的定义(可以参见tag_attr html_allow这个数据结构,位于wget源码html.c中)。而reset-domain针对的是可能存在的文本替换——而无论对象是否是.html,或者是否是真实的url链接。
经过这两轮的处理(generate和reset-domain)之后,事实上整个./static
目录下的文件已经可以作为静态页发布了。确切地说,你已经可以使用下面的命令来部署本地git仓库,将它推到你的主页YOURNAME.github.io
中去了:
> bash makesite.sh --deploy-now
然而makesite.sh脚本还在这个操作之前插入了一个--short-path
——我想你已经注意到这一点了。
这个short-path的目的是将Ghost生成的类似于/your--post-full-title----as-slug/index.html
这样长的“目录名+文件名”变得短一些。它基本的想法就是让主页根目录下不要太多的目录,因此将这些目录中的index.html上移到它们的父目录中——对于所有的posts来说,其实也就是根目录下。
这个过程其实有一个更好的解决方案,就是将所有这些文件移入到/posts/your--post-full-title----as-slug.html
,这样一来主页根目录下就只有一个posts目录了。我尝试过,但之后放弃了,因为我写不出一个有效的正则表达式来替换所有“其它”页面中的url——到该页面的新位置。
好吧,总而言之,我们做了一点工作(尽管实际上这是效率最低的一个步骤)。所以你还是可以在部署之前尝试一下:
> bash makesite.sh --short-path
6.3.1 更短的url
我的主页aimingoo.github.io
中其实使用的是更短的url地址,而并不是Ghost中缺省地按照文章标题通过拼音转换而来——后面这种文件名生成得太长太难看了。这种『更短的url』其实是通过为每个post设置它独自的slug属性而得到的,这需要为每篇文章在Ghost后台管理界面去编辑Post的属性。
这也是上一篇博客中提到的putrefy.js
这个工具(在这里)中会有一个SLUG_FROMID
参数的原因。当配置这个参数为true时,你从旧博客中导入的文章就将自动地以author_id
作为前缀,并加上post_id作为slug了——我的博客就是用这种方法来导入的。当然,你也可以将SLUG_FROMID
配置为别的什么字符串来作为前缀。
但是,你在Ghost后台新添加的文章,就需要你手工地改slug了。这个今后我会发布个小工具来自动化的,这里暂且不提。
6.4 关于patchme.sh
这是在makesite.sh中留下的一小处补丁程序。你可以编写一段shell代码(放在makesite.sh同目录中就可以了),让makesite.sh在正式地deploy-now操作之前,由你自己来对./static
目录中的页面做些修补。这偶尔也是必要的,例如我现在这篇文章是在介绍Ghost,那就不可避免地会用到localhost:2368
这样的url地址,而按照Buster和makesite.sh的规则,它们就可能被替换成线上Github仓库中的地址了——所以需要one by one地patch。
当然,你也可以写点别的什么代码。
尤其是……程序员总想干点什么黑活之类的啦。
你懂的。