这里记录怎么利用Github Pages以及jekyll构建个人网站。
Jekyll
Jekyll是一个生成静态网站的工具,好像是Github Page的官方工具,用来把markdown文件转换为网页文件。
安装Jekyll
Jekyll是使用编程语言ruby写的,所以首先要安装ruby,同时它的包管理工具gem也会安装上。在MacOS上,安装了命令行工具后这些都自动安装了,但是这个自带的ruby都在系统库,每次安装都要sudo很麻烦,所以还是用brew安装一个:
brew install ruby
然后在.zshrc里改PATH加上路径opt/homebrew/opt/ruby/bin
。可以用which ruby
检查是是不是brew的ruby。有了ruby后,用以下命令安装Jekyll:
# 你可能需要换源
# gem sources --add https://gems.ruby-china.com/ --remove https://rubygems.org/
gem install jekyll --pre # 安装最新版
# 在macos上,用brew的ruby安装的,安装路径在opt/homebrew/lib/ruby/gems/3.3.0/bin里,也得改PATH
# 可以通过gem env查看gem会把包安装在哪
然后就可以使用jekyll命令了:
jekyll
我的环境版本:
- jekyll 4.3.3
- bundle 2.5.9
- ruby 3.3.1
准备主题
要写博客,首先要准备一个主题,然后基于这个主题去做个性化的设置。主题可以在jekyllthemes网站上找,然后把对应的github仓库clone到本地。如果要做学术主页,AcademicPages就很好。不过我是想写博客记笔记,所以挑了一个复杂一些的主题。这里建议检查选择主题对公式、代码的支持怎么样,有的主题太简陋了,不支持公式,而且代码的渲染很丑。还要看看对中文的支持怎么样,有的主题英文好看,但是用中文会很丑。
我找了两个对中文、公式、代码支持比较好的主题:chirpy和 TeXt。最后选择了TeXt。
把github仓库clone到本地后,使用下面的命令安装依赖(会根据当前目录的Gemfile安装):
bundle
# ruby安装依赖是真的慢
# bundle也可以换源
# bundle config mirror.https://rubygems.org https://gems.ruby-china.com
这里可以修改_config.yml里的一些信息,比如替换名字、链接之类的。 最后运行:
bundle exec jekyll serve
# 这个会生成网页,都在_site文件夹里
就会出来一个链接,点这个链接就能看到网页了。到这里说明主题可以成功使用。
把主题发布到github上
接下来要把主题放到github.io上,其实只要把clone的主题push到自己的github.io仓库上就可以了,github会自动编译的(这个过程可能会由于远程的环境和本地环境不同而导致bug,这个就得自己解决了)。
写博客
主要要改的是_config.yaml和_posts里的md文件。
_config.yaml是用来设置的,比如设置博客的标题、自己的邮箱等等,选择主题之类的东西,这个是全局的设置。
写博客只需要在_posts文件夹里加一个markdown文件就可以了,一个markdown对应一篇博客,文件名格式是YYYY-MM-DD-youre-title.md
,这个格式是必须的,因为会把它转化为url的一部分。然后运行:
bundle exec jekyll build
# bundle exec jekyll serve会动态检查_post里面的文件修改并编译
就可以把它转换成html文件,生成的文件都在_site文件夹里。
Jekyll markdown
Jekyll的markdown和一般的markdown有一些区别。原因在于Jekyll使用kramdown(一个ruby的库)来把markdown转换成html,这个kramdown本身和markdown语法有点区别(markdown的标准语法这么没牌面吗)。除此之外,Jekyll在markdown的基础上加了liquid这个模板语言,于是转换过程是markdown+liquid → markdown → html。
这里介绍一些比较重要的krmarkdown语法,其余的边用边搜吧:
-
开头需要加一些属性告诉jekyll:
--- title: "Post example" tag: algorithm ---
这个叫YAML Front Matter。
-
使用markdown的代码块```python会没有语法高亮,原因是liquid导致的,具体原理不清楚。解决办法是开头加上
render_with_liquid: false
。另外注意要用小写,比如```C++不行,但是```c++可以。这个的缺点是没有行号。有点奇怪,我一开始没有高亮,加了这个语句后就有了,但是删了以后还是有。
- 高亮语句
重要提示: 重要、紧急、致命提示信息 {: .success}
这里success可以换成error、warning、info。
- mathjax的
|
要用\|
才会渲染成|
这里有两个比较完善的教程:
- https://hangx-ma.github.io/2023/05/18/Jekyll-TeXt-config.html#1-代码块-liquid-代码误解析
- https://alpha1e0.github.io/其他/welcome-to-jekyll/
网站原理
liquid是一个模板语言,用来定义html的模板。这些主题用liquid写好了网站长什么样,而写好的markdown博客只是把模板里的变量替换掉,变成html文件。YAML Front Matter或者_config.yml里面的设置是一些变量,比如一个markdown文件对应到liquid模板里是page
变量,而_config.yml是site
变量,site
变量是全局的。
每个页面的变量以及页面之间的继承关系可以看https://kitian616.github.io/jekyll-TeXt-theme/docs/zh/layouts
个性化设置
参考这个主题的官方教程: https://kitian616.github.io/jekyll-TeXt-theme/docs/zh/quick-start
基础改动
-
导航栏:改_data/navigable.yml
-
底栏:改_data/local.yml
-
新增的文件、文件夹都会被编译到_site文件夹里面成为网页的一部分
- assets也会被放到_site里面,但是以
_
开头命名的文件不会 - 分页只能对index.html进行分页
- assets也会被放到_site里面,但是以
-
摘要字数设置
博客列表会显示博客开头的一部分字作为摘要。修改_include/article-list.html里面的第一行设置摘要字数(我把350改成200):
html
另一种控制方式是在markdown里面加<!—more—>
,它前面的内容会被作为摘要。
添加一键复制代码
参考这里。但是这样做了之后每次添加代码块都要在外面加一层:
<div class="copyable" markdown="1">
</div>
这样太麻烦,我选择用javascript自动给代码块加这个,需要修改的是_includes/scripts/lib/copy-to-clipboard.js里面开头的一段。原本这段代码是:
var snippets = document.querySelectorAll('pre');
[].forEach.call(snippets, function(snippet) {
if (snippet.closest('.highlight') !== null) {
snippet.firstChild.insertAdjacentHTML('beforebegin', '<button class="btn" data-clipboard-snippet><i class="far fa-copy"></i></button>');
}
});
考虑到代码块对应的html长这样:
<div class="language-sh highlighter-rouge">
<div class="highlight">
<pre class="highlight">
<code>代码</code>
</pre>
</div>
</div>
我们需要给pre的父元素添加按钮,并在外层添加带有copyable类的div块,代码需要改成:
var snippets = document.querySelectorAll('pre');
[].forEach.call(snippets, function(snippet) {
snippet.parentNode.insertAdjacentHTML('beforebegin', '<button class="btn" data-clipboard-snippet><i class="far fa-copy"></i></button>');
snippet.style.overflow = 'scroll'; // 让代码块有滚动条
target = snippet.parentNode.parentNode;
var wrapperHTML = '<div class="copyable" markdown="1">' + target.outerHTML + '</div>';
target.outerHTML = wrapperHTML;
});
这里我把if
判断null
也去掉了,因为既然出现了代码块,肯定会有父节点的。
logo替换
准备好自己的log,把原本的一些图片替换掉,具体要替换下面3个位置的图片:
-
assets里的一堆图片
-
assets/logo里面的图片
-
_include/svg/logo.svg(影响的是网页header)。
assets里面的一堆图片可以在favicon生成,只需要上传一个图片,会生成相应的各种尺寸图片。浏览器标签页的logo叫favicon,如果想要看到它更新需要在设置里删掉浏览器缓存的图片。
添加评论
TODO
代码主题替换
TODO
问题记录
bundle安装依赖报错
-
解决办法是直接把Gemfile.lock删了,没啥影响,因为这个是运行bundle自动生成的,等会运行bundle会生成一个。
-
Gemfile里的版本问题
把里面的~>换成>=,前者表示更高的小版本可以,后者表示更新的版本都可以。这样修改了对依赖的版本约束,新版jekyll的也能用了。但是会出现一些deprecated warning。
deprecated warning
全都是因为sass里的除法:
($button-height-xl - map-get($base, font-size-xl)) / 2
在外面套一个calc
函数就可以了,注意percentage
里面不能用calc
,比较好的解决办法是把percentage(xxx)
换成calc(xxx * 100%)
,这里xxx
表示一个表达式。
公式渲染失败
原因是mathjax加载太慢,先尝试把cdn的源换掉:
sources: unpkg # bootcdn (default), unpkg
但是换掉之后也挺慢的,这2个cdn好像都不太行。现在用的是2.7.4版本的mathjax,据说3.0版本以上性能提升很大,所以想办法升级到3.0吧,并且把mathjax弄到本地。
引入mathjax的代码在_includes/markdown-enhancements/mathjax.html里面最后一行:
<script type="text/javascript" src="" async></script>
而_sources.mathjax的链接是_data/variables.yml里面的,所以在assets文件夹放mathjax,再把这个链接改了就行。
我把mathjax存放在/assets/third-party/mathjax,把链接也改成这个,但是发现这样无法渲染行内公式,原因是mathjax的配置问题。在_includes/markdown-enhancements/mathjax.html这个文件里面有一部分javascript是用来设置mathjax,里面包含了行内公式的支持。但是它指定了<script type="text/x-mathjax-config">
这里的type,3.0版本不能这么指定。另外原本的mathjax 2的配置语法也不能用了,要改成新的。
总之要改成:
<script>
MathJax = {
tex: {
inlineMath: [['$', '$'], ['\\(', '\\)']] // 支持 $...$ 和 \(...\) 作为行内公式分隔符
},
svg: {
fontCache: 'global' // 使用全局字体缓存
}
};</script>
换成3.2.2版本的mathjax后渲染确实变快了。
无法显示liquid语言
在写markdown文件里面添加代码块,如果代码块里面有liquid语法会导致渲染失败,解决办法是在markdown文件开头加上
render_with_liquid: false
。
cdn太慢
侧边目录加载慢、归档页面加载慢都是因为相关功能依赖于jquery,而jquery是通过cdn获取的。mermaid加载也慢,也是cdn的锅。为了加速,我把这些第三方库都放到assets/third-party里,然后相应的把_data/variables.yml里面的链接都改成本地地址就可以了。