在上一篇文章里面刚说好不要又是一篇技术博客,结果,可能我今天就要水一篇了……主要原因是觉得用了LoveIT这个主题之后,觉得还是有点美中不足,所以自己动手修改了一下。修改完了觉得,总得找个地方记录一下,以免,之后自己忘记怎么搞。下面说的修改都以LoveIT为例,其他的主题可以参照修改。
Tip
除非打算提交PR,否则不建议在主题的文件夹内直接进行修改,不然会给日后更新主题带来很多的麻烦。推荐把主题内需要修改的文件复制到站点根目录对应位置内(例如:/themes/LoveIt/layouts/partials/single/footer.html -> /layouts/partials/single/footer.html)之后进行修改。hugo在生成站点的时候,会优先使用根目录下的同名文件覆盖主题文件。
1. 相关文章
以前用WordPress的时候,可以显示相关文章的推荐。我觉得这个功能挺好用的,于是想着我也要增加这个功能。因为hugo是全静态的,所以这个实现起来似乎有些难度。google了一圈发现了这篇文章:How to show related posts in Hugo。看了一下原理,似乎是通过文章的tag来实现的。
那就,照着那篇文章里面的代码,稍微修改一下吧:
需要修改的文件是/layouts/partials/single/footer.html
在合适的位置插入下面代码:
|
|
上面的代码默认会显示最多5篇相关文章,如果某一篇文章不需要显示相关文章的话,可以在文章的front matter中手动输入"RelatedPosts: false"来禁用相关文章的显示。
PS. 我后来又发现hugo-theme-meme这个主题的config.toml里面有相关文章的部分,可以通过文章的分类,标签和发布日期来设定权重,感觉更加全面一些了。
2. 全文搜索(Algolia)
感觉这个是最难的部分,我搞了好久好久啊……最大的难点就在于,如何生成全文的索引。Algolia怎么注册什么的,网上铺天盖地都有,就不再赘述了。下面假设已经注册好了Algolia,同时也已经有了对应的API Keys。
在config.toml里面需要设置下面这些内容:
|
|
同时,在[outputs]中,home增加Algolia。修改完毕应该长这样:
|
|
2.1 生成索引
生成文章的索引是实现搜索的第一步,也是最麻烦的一步。
麻烦的点主要在于,Algolia免费的服务限制了每一条记录的大小不能超过10 KB。所以,对于一些比较长的文章来说,如果要实现全文索引,那就势必牵涉到如何分割记录这个问题。
Algolia官方的建议是可以按照每一段来分割记录,并且针对WordPress和Laravel给出了教程。可惜的是,这些都是针对PHP的教程,没法移植到hugo上面。我于是google了一遍,发现一个俄罗斯的哥们写了个Gulp脚本,按照副标题来切割记录。然而……我很多的文章并没有副标题……然后我又发现了这篇文章。这个哥们也跟我有同样的困扰,于是采用了一个机智的方法,利用delimit函数,每1000个空格截断记录。我尝试了一下,可耻地失败了。失败原因:中文他没有空格啊……
不过虽然照抄代码失败了,思路还是可以借鉴的。机智如我想到:💡英文用空格来截断,主要是为了防止一个单词中途被切开,那中文并没有这个问题啊!我的博客,绝大多数的内容都是中文的,所以,直接截取若干个字符,应该就好了吧!至于为数不多的几篇英文博客,就,抓大放小吧……如果有更好的切割长文章的方法,强烈欢迎大家一起讨论。
简单爬了一下hugo的文档,发现了substr这个函数挺有潜力的。不过似乎substr不能用在Page.PlainWords上面,没关系,那就改用Page.Plain吧。
Page.Plain得到的结果里面有一些转义的字符需要修改一下。我就直接贴一下我的模板吧:
|
|
把模板保存为/layouts/{?_}defaults/list.algolia.json。运行hugo命令之后就会在/public文件夹下生成algolia.json,可以上传到algolia了
2.2 上传索引
上传到algolia相对来说就比较简单了。我用的是atomic-algolia。首先安装npm,然后在站点根目录下面运行:
|
|
npm init是用来生成默认的package.json,基本上一路回车就行了。运行运行完这两个命令之后,打开package.json文件,在"scripts"这部分增加一句"algolia": "atomic-algolia"。修改完毕之后应该长这样:
|
|
完成之后,还需要新建一个.env的文件,告诉atomic-algolia一些信息:
ALGOLIA_APP_ID={{ YOUR_APP_ID }}
ALGOLIA_ADMIN_KEY={{ YOUR_ADMIN_KEY }}
ALGOLIA_INDEX_NAME={{ YOUR_INDEX_NAME }}
ALGOLIA_INDEX_FILE=public/algolia.json
填写并保存之后,可以尝试把索引提交给Algolia了:
|
|
如果一切正常,那么应该看到的是类似于下面这张图片(我懒得截图,用了上面那个blog的截图):
2.3 修改Algolia的设置
上传完毕索引之后,还需要在Algolia里面设置一下。点击Indices,然后找到Configuration这个tab。主要修改下面几个选项:
-
Searchable attributes
这个选项用来告诉Algolia,在哪些索引里面进行搜索。比如,我不需要Algolia在日期和URL里面进行搜索(一般人都不需要吧),所以我的选项是title,tags,content和categories。
-
Ranking and Sorting
这个主要是排序,除了Algolia自己默认的之外,我还增加了date。优先显示最近发表的博客。
-
Duplication and Grouping
我们之前把一条博客拆分成了好多条索引,因此默认情况下Algolia如果在同一篇博客的不同索引找到了同一个关键词,会把这些索引都显示出来。这就有些没必要了。所以可以在这里进行设置,把Distinct设置为true,然后Attribute for Distinct设置为url,或者title。
-
Highlighting
这里最重要的是设置搜索结果中高亮的tag。Algolia默认用了
<em>
和</em>
来进行高亮,但是LoveIt(或者hugo?)用了这个标签来标记斜体。因此需要修改一下。于是我把标签修改成了<m>
和</m>
。 -
记得点Review and Save Settings来保存修改
2.4 和Netlify结合
每次更新blog之后手动生成和上传索引肯定不是一个方便的解决方案。好在我的博客采用了Netlify来部署,使用Netlify的话使得部署更方便。怎么注册Netlify,如何把Netlify和GitHub整合也不是这篇blog要cover的内容。下面的内容假设你已经可以成功在Netlify上面部署博客站点了。
首先,在settings的Build & deploy里面找到Environment,然后点击Edit variables。点击New variables,把刚才.env里面的4个变量分别填进去就行了。类似这样:
之后,修改根目录下netlify.toml,把{?[}build]下面的command行修改为:
command = "hugo --gc --minify && npm install atomic-algolia --save-dev && npm run algolia"
这样,下次更新完博客之后,netlify就会自动生成索引,并且提交给Algolia了。
2.5 为主题增加搜索页
这部分吧,主要难点在修改css……熟悉我的都知道我是个学财务和金融做咨询的,体健貌端思想开放,技术宅只是业余爱好。好在做咨询的,对于Google的使用还算略有一些心得。摸爬滚打误打误撞之后,居然也给我改出来了……
之前解决了我们分割记录问题的哥们也给了一个代码,做出了一个电脑上挺好用的即时搜索框。可惜这个框在手机上不太好用,所以我决定还是新建一个搜索页,专门用来搜索吧。
首先,在/content下面新建一个search.md文件,内容如下:
|
|
日期设置为1970年的原因是搜索页面在输入关键词前,会显示最近更新的10篇文章。这样设置可以避免搜索的时候先显示了这篇文章。
然后,在/layouts下新建static文件夹,放入search.html。这个文件比较大,就不贴在这里了点这里下载。
接下来是修改css,否则的话这个搜索丑丑的。我直接用了Algolia给的示例主题进行修改。文件太大我也不贴了,点这里下载之后放在/assets/css/_page中。记得修改_index.scss文件来引入_search.scss
最后,需要在导航栏中引入搜索页。这个超级简单,直接在config.toml中增加一项[[menu.main]]:
[[menu.main]]
url = "/search/"
name = "搜索"
weight = 6
pre = ""
完成之后,搜索部分就搞定啦!
3. PWA
PWA纯粹是,好玩……是我在看hugo-theme-meme的时候发现的。所以,具体过程参考这篇文章就行了。
说几个需要注意和修改的地方:
-
因为之前生成了algolia.json,如果内容多的话,这个文件还挺大的。虽然我不知道这个文件会不会被缓存,但是考虑到我其实并没有其他用到json的地方,所以我还是决定在gulpfile.js里面的globPatterns部分删掉了json。
-
我增加了Google的PWA Compact,可以自动根据manifest.webmanifest来生成各种东西支持其他浏览器。这么做需要修改/layouts/partials/head/link.html,增加下面这一行:
1
<script async src="https://cdn.jsdelivr.net/npm/pwacompat@2.0.10/pwacompat.min.js" integrity="sha384-I1iiXcTSM6j2xczpDckV+qhhbqiip6FyD6R5CpuqNaWXvyDUvXN5ZhIiyLQ7uuTh" crossorigin="anonymous"></script>
记得检查一下,link.html里面那个manifest文件的文件名是否和/static里面的文件名一致。具体叫manifest.json还是site.webmanifest还是manifest.webmanifest无所谓,只要文件名一致就行。
-
注册Service Worker和提醒的代码我放在了/layouts/partials/footer.html里面,照抄就行。
-
CSS脚本我原封不动地放在了/assets/css/_core/_pwa.scss里面,然后记得修改/assets/css/style.template.scss来引入增加的scss文件。
老规矩,测试通过之后可以交给Netlify。还是修改netlify.toml文件,增加命令。和Algolia搜索的相关命令整合之后,这个文件现在长这样:
|
|
更新成功之后,可以用Lighthouse来检查一下。如果提示有任何错误,修正即可。
4. Disqus代理
由于众所周知的原因,国内现在访问不了disqus,和一些其他的网站了。所以除了科学上网之外,还需要科学评论……采用的方案是SukkaW/DisqusJS。这是一个超轻量级的代理,可以自动检测访客的Disqus可用性,自动选择加载原生Disqus(评论完整模式)和DisqusJS提供的评论基础模式。
Disqus代理的另外一个选项是szhielelp/disqus-proxy。这个方案的优点是可以匿名评论,可是deal breaker是他用了bootstrap CSS,会和主题的CSS冲突。因此作为一个懒人,我断然决定放弃。
DisqusJS部署起来超级简单,我后端用ZEIT Now,只需要一个now.json文件就行了。不需要下载now的教程参照这里。看上去只需要部署一次,一劳永逸。
前端的话,也不复杂,只需要在config.toml里面增加几个变量,然后动一动/layouts/partials/comment.html这个文件就行了。
config.toml增加的变量:
|
|
变量说明:
变量名 | 说明 |
---|---|
enable | 是否启用Disqus评论系统(true/false) |
proxy | 是否启用DisqusJS代理(true/false) 注意:如果没有在上面启用Disqus评论系统,那么即使这里设置为true,DisqusJS也不会启用 |
shortname | 你的Disqus Forum的shortname,你可以在Disqus Admin - Settings - General - Shortname获取你的shortname |
api | 搭建的后端api地址(https://xxx.now.sh/) |
apikey | Disqus Application中API Key |
admin | 你的站点的Disqus Moderator的用户名(也就是你的用户名)。你可以在Disqus - Settings - Account - Username获取你的Username |
adminLabel | 你想显示在Disqus Moderator Badge中的文字。该配置应和Disqus Admin - Settings - Community - Moderator Badge Text相同 |
/layouts/partials/comment.html的修改:在<div id="disqus_thread"></div>
下面插入这段代码:
|
|
这里没有引入DisqusJS默认CSS的原因是,LoveIt会根据系统设置启用夜晚模式,而夜晚模式下DisqusJS的默认颜色就比较刺眼了。解决方式是下载这个文件,保存到/assets/css/_partial/_single/,最后在同目录下的_comment.scss最后增加一句代码@import "_disqusjs.scss";
来引入修改之后的scss文件。
需要提一下的是,默认在development环境下LoveIt是不会渲染Disqus的。所以要么直接在production里面测试,要么暂时把{{- if $scratch.Get "production" | and (ne .Site.Params.comment.enable false) | and (ne .Params.comment false) -}}
里面的production改成development。部署之前记得改回来就好。
5. 懒人方案
说了那么多,如果上面这些功能都想要的话,我在GitHub上面fork并修改了LoveIt的源码,直接用git submodule add --depth 1 https://github.com/dreamsafari/loveit.git themes/LoveIt
,然后修改config.toml即可。
6. 后话
选择LoveIt这个主题,很大一部分的原因是因为丰富的Shortcodes支持。考虑到我目前心水hugo-theme-meme这个主题,所以估计接下来一段时间里面,如果有空的话,会尝试一下能不能把Shortcodes和这些功能移植到meme上面吧……关于这些功能在LoveIt上面的实现,如果有问题的话大家在下面留个言吧。