博客优化:本地调试博客站点 & 文章间通过相对路径跳转
source link: https://blackdn.github.io/2024-02-21-Blog-LocalDebug-RelativeLink-2024/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
“待到明年又一春,桃花红,梨花白,菜花黄。”
博客优化:本地调试博客站点 & 文章间通过相对路径跳转
兄弟萌,我愿称之为最有技术含量的一篇博客优化 TAT
不论是本地调试还是相对链接都磕磕碰碰,Google都快被我翻烂了
不过总算是小有成果,总感觉被迫半入门了 Jekyll 和 Liquid =。=
本地调试(on Mac)
说来奇怪,本地调试这么重要的东西,应该更早些想到的
以往对博客的一些修改,我都是改完直接 push
到 github 上,不仅要等待 github 对站点进行编译后才能生效,要是有一些不易发觉的小错误,又得重新提交,比如写错个日期、标签啥的。
更别提想测试一些功能或代码了,比如之前给文章标题添加描边、给网站添加搜索功能了,都不知道到底 push
又 revert
了多少次。
所以这次干脆一不做二不休,直接实现本地调试,以后就不需要这么多幺蛾子咯。
添加本地的 Gemfile
首先,我们知道我们的 GitHub Pages 站点是通过 Jekyll 生成的,按照正常运行 Jekyll 项目的套路,我们只需要先运行 bundle install
安装依赖包,然后再 bundle exec jekyll serve
启动本地调试即可。
遗憾的是,不出意外的话我们的 bundle install
会报错,提示当前目录没有 Gemfile
文件,这个文件就是包含项目所需的依赖,类似 packages.json
之于 npm
。
由于 GitHub Pages 在 GitHub 端编译生成网站,所以它那边自带 Gemfile
,不需要我们本地维护,因此我们的博客项目文件里是不包含 Gemfile
的。但是我们现在要本地调试,不得不需要这个 Gemfile
,这就尬住了。
不过没关系,有个好消息,GitHub Pages 的 Gemfile
是开源的:pages-gem!
简单来说,我们没有 Gemfile
,就新建一个 Gemfile
,然后为我们的 Gemfile
添加这一行:
gem 'github-pages', group: :jekyll_plugins
虽然我们的 Gemfile
只有一行,只包含了 github-pages
这个包,但是这个包中又有很多其他的依赖包,指定了 jekyll
、kramdown
、liquid
等依赖及其版本,所以我们只用加这一行就行了。
安装不同版本的ruby
然后总可以 bundle install
了吧,但是不出意外,还是会报错,类似于没有权限啥的:
You don't have write permissions for the /Library/Ruby/Gems/2.3.0 directory.
原因是 Mac 有一个内置的系统ruby,为了安全性和稳定性考虑,通常情况下不会允许我们自己对其进行修改,包括为其添加依赖包。
推荐的操作是安装一个和系统ruby不冲突的另一个版本的ruby,然后用这个ruby进行操作。
为此我们需要安装这两个工具:ruby-install
和 chruby
。两者都可通过 homebrew
安装
> brew install ruby-install chruby
> brew list | grep 'ruby'
chruby
ruby-install
ruby-install
用来安装指定版本的ruby, chruby
方便在各个版本的ruby中切换。
安装成功后我们先运行: ruby-install ruby
这个命令会帮我们安装最新版的ruby,我安装的是3.3.0
。
然后运行:chruby
,可以查看当前可用的ruby版本,指定版本就可以进行切换。如果要切换回系统的 ruby,运行 chruby system
即可。
> chruby
ruby-3.3.0
> chruby 3.3.0
> chruby system
chruby
本质上是修改系统的PATH变量,修改指向的 ruby 位置。
进行本地调试
在调试之前,根据 GitHub 官方文档的:使用 Jekyll 在本地测试 GitHub Pages 站点,如果安装的 ruby 是 3.0
及以上,需要额外运行 bundle add webrick
,在 Gemfile
中添加 webrick
这个依赖包。因为我是3.3.0
嘛,所以就加一下。
之后 bundle install
和 bundle exec jekyll serve
应该就可以正常运行了(可能需要加个 sudo
)
不过要注意的是,bundle install
会根据我们的 Gemfile
生成一个 Gemfile.lock
文件,我们最好不要上传 Gemfile
和 Gemfile.lock
,因为 GitHub 那边有自己的 Gemfile
,免得发生一些不必要的冲突。
此外,启动本地调试的时候会生成一个 _site
文件夹,里面是 Jekyll 根据我们post
目录里的文章生成的文章页面,也不需要上传。
因此在 .gitignore
文件中最好有以下内容:
...
# debug file
_site
# Ignore local Gemfile as GitHub Pages has its own Gemfile
Gemfile
Gemfile.*
现在运行bundle install
和 bundle exec jekyll serve
:
> sudo bundle install
Bundle complete! 2 Gemfile dependencies, 97 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
> sudo bundle exec jekyll serve
Configuration file: /xxx/BlackDn.github.io/_config.yml
Source: /xxx/BlackDn.github.io
Destination: /xxx/BlackDn.github.io/_site
Incremental build: disabled. Enable with --incremental
Generating...
done in 2.303 seconds.
Auto-regeneration: enabled for '/xxx/BlackDn.github.io'
Server address: http://127.0.0.1:4000/
Server running... press ctrl-c to stop.
运行成功后,命令行会保持对站点的监听,在 Auto-regeneration: enabled
的前提下,我们的站点会保持热更新,对代码文件的修改会实时更新在页面上(可以手动刷新一下,毕竟 Jekyll 渲染的是静态页面)
大功告成!访问 http://127.0.0.1:4000/
就可以看到自己的网站啦~
纠正语法错误
我们运行 bundle exec jekyll serve
后,命令行可能会抛出一些警告,提示我们有编译错误,可以到对应的文件里看看,是不是有一些Liquid语法上的错误。
比如在 {% %}
中间的变量是不需要再用{{}}
包裹的,我的一个错误就是:
{% if tag[1].size > {{site.featured-condition-size}} %}
报错,需要改成:
{% if tag[1].size > site.featured-condition-size %}
Markdown链接:文章间以相对路径跳转
这其实是个说大不大,说小不小的点。
以往的文章中,比如我在文章A中有一个跳到文章B的链接,我都是以绝对路径进行跳转的, Markdown
源码是这样:
[Angular JS 入门指南](https://blackdn.github.io/2024/02/06/Angular-Intro-Component-2024/)
其中的https://blackdn.github.io/
是 Jekyll 的 baseurl
,后面的内容则是 Jekyll 通过解析文件名得到的。
当然用绝对路径多少有点弊端,比如我以后修改了baseurl
,或者我不用GitHub Pages,换了个平台,或者自己租服务器搭博客网站,那所有绝对路径的内容都得再改。
另外还有一个理由,就是我想用上 Obsidian(我用的 Markdown 编辑器)的 Graph View 功能,它会根据文章间的互相引用生成一个可视化的图,但是只有使用相对路径才能让Obsidian 的 Graph View 自动识别并生成图:
也就是说,我希望能够满足以下两点:
- 使用相对路径实现文章间的跳转(可以被 Obsidian 识别并生成图)
- Jekyll 可以正确渲染链接并在页面跳转
接下来是我从发现问题到解决问题的心路历程,有些绕,有些冗杂,因此也可以直接移步去看最后的总结。
当前 Jekyll 解析相对路径带来的问题
有以下三种 Markdown 相对路径链接, Obsidian 都可以识别并跳转,也可以生成图:
[Jump to XXX](2024-02-06-xxx-2024)
[Jump to XXX](./2024-02-06-xxx-2024)
[Jump to XXX](../2024-02-06-xxx-2024)
反观 Jekyll,源文件名为 2024-02-06-xxx-2024.md
的文章,我们将其看成 {year}-{month}-{day}-{title}
的格式 ,它会被 Jekyll 解析成:https://blackdn.github.io/2024/02/06/xxx-2024/
即 {baseurl}/{year}/{month}/{day}/{title}
的格式
也就是说,目前的 Jekyll 会根据年月日依次创建出子目录。虽然子目录的形式看着更舒服,更易读,但同时也阻止我们直接套用上面的相对路径链接。
举个🌰,我们正在浏览的某篇文章源文件名为 2022-02-22-Example-2022.md
,那么我们当前 url
为 https://blackdn.github.io/2022/02/22/Example-2022/
,这个时候点击上面的三行 Markdown 跳转后,url
分别会变成:
源文件:2022-02-22-Example-2022.md
当前url:https://blackdn.github.io/2022/02/22/Example-2022/
点击:[Jump to XXX](2024-02-06-xxx-2024)
或 [Jump to XXX](./2024-02-06-xxx-2024)
跳转到url:
https://blackdn.github.io/2022/02/22/Example-2022/2024-02-06-xxx-2024
点击:[Jump to XXX](../2024-02-06-xxx-2024)
跳转到url:
https://blackdn.github.io/2022/02/22/2024-02-06-xxx-2024
而正确的url:https://blackdn.github.io/2024/02/06/xxx-2024/
显然,上面跳转后的url
都是错误的,都会跳到404页面。
总而言之,相对路径在 Markdown 中是可行的,但是被 Jekyll 解析成 url
后出了错,主要存在着两个问题:
- 年月日带来的子目录让我们的相对路径不能正确地找到位置,总不能写成
[Jump to XXX](../../../../xxx)
吧,太抽象了=。= - 我们无法将源文件名中的年月日在 Markdown 的链接中解析成子目录(就是没法将年月日中间的
-
替换成/
)
配置 Jekyll 的 Permalinks
定位到问题后,似乎就变得简单了些,我干脆就不要年月日的子目录了。
如果 Jekyll 能将 {year}-{month}-{day}-{title}
的源文件解析成 {baseurl}/{year}-{month}-{day}-{title}
,那所有问题就迎刃而解了。
没有了子目录,所有文章的 url
都变成 {baseurl}/{源文件名}
,那么只要在 Markdown 是 ../{其他文件名}
的形式,就可以跳转到其他文章了:
源文件:2022-02-22-Example-2022.md
当前url:https://blackdn.github.io/2022-02-22-Example-2022/
点击:[Jump to XXX](../2024-02-06-xxx-2024)
跳转到url:https://blackdn.github.io/2024-02-06-xxx-2024/
合理!
那么我们要如何修改 Jekyll 的解析方式呢?
简单,来到项目根目录的 _config.yml
文件,定位到 permalink
属性:
# in ./_config.yml
...
# Build settings
permalink: pretty
paginate: 10
...
这个 permalink
规定了 Jekyll 要如何将源文件名解析成url
(下面的 paginate
属性规定了每页有几篇文章,可以自己改着玩)
Permalinks简介
所谓 permalink
,其实就是每个文章页面的 url
格式,详见官方文档:Permalinks
当一篇文章被 Jekyll 解析后,会生成以下变量:
变量 | 作用 | 开始支持的版本 |
---|---|---|
year |
源文件名中的年份,如2024 |
|
short_year |
源文件名中的年份后两位,如24 |
|
month |
源文件名中的月份,如02 |
|
i_month |
源文件名中的月份,不含首位0,如2 |
|
short_month |
源文件名中的月份简称,如Jan |
|
long_month |
源文件名中的月份全称,如January |
4.0 |
day |
源文件名中的日期,如03 |
|
i_day |
源文件名中的日期,不含首位0,如3 |
|
short_day |
源文件名中的日期简称,如Sun |
4.0 |
long_day |
源文件名中的日期全称,如Sunday |
4.0 |
y_day |
源文件名中的日期在整年中的天数,范围从001-366 |
|
week |
源文件名中的日期在整年中的周数,范围从01-53 |
4.0 |
w_day |
源文件名中的日期在整年中的周数,范围从1-7 |
4.0 |
hour |
文件头中date 所定义的小时,范围从00-23 |
|
minute |
文件头中date 所定义的分钟,范围从00-59 |
|
second |
文件头中date 所定义的秒,范围从00-59 |
|
title |
源文件名中的标题 | |
slug |
也是源文件名中的标题,和title 不同的是,数字和字母外的字符会被取代为连字符- |
|
categories |
文件头中定义的类型,如果有多个则依次创建目录,如/category1/category2 |
|
slugified_categories |
也是文件头中定义的类型,数字和字母外的字符会被取代为连字符- |
4.1 |
output_ext |
源文件扩展名,如.md ,不怎么用到 |
有了这些变量后,我们可以自由组合,来自定义文章的url
。要注意的是,变量前面要加上冒号作为前缀,比如:
permalink: /:year_:month_:day_:title
源文件名:2022-02-22-Example-2022.md
url:https://blackdn.github.io/2022_02_22_Example-2022
permalink: /:short_year/:i_month/:i_day/:title:output_ext
源文件名:2022-02-03-Example-2022.md
url:https://blackdn.github.io/22/2/3/Example-2022.md
此外,Jekyll 提供了一些内置的模板
名称 | 模板内容 | 开始支持的版本 |
---|---|---|
date |
/:categories/:year/:month/:day/:title:output_ext |
|
pretty |
/:categories/:year/:month/:day/:title/ |
|
ordinal |
/:categories/:year/:y_day/:title:output_ext |
|
weekdate |
/:categories/:year/W:week/:short_day/:title:output_ext |
4.0 |
none |
/:categories/:title:output_ext |
如果我们没有指定 permalink
,那么 Jekyll 默认将使用permalink: date
weekdate
中的W
是作为:week
的前缀,没啥特殊意义。
配置Permalink
回到我们的 _config.yml
文件,看到我们当前是 permalink: pretty
而我们现在需要得到 {baseurl}/{year}-{month}-{day}-{title}
的url
,所以只需要修改成:
permalink: /:year-:month-:day-:title/
如果正在本地调试,修改了 _config.yml
配置文件,需要重启一下服务器,重新运行bundle exec jekyll serve
最后只用保证以后在写 Markdown 的时候,先返回上级目录,再跳转到对应文章的相对路径的形式即可:[Jump to XXX](../2022-02-03-XXX)
这下子,我们的相对路径的文章链接,在 Jekyll 和 Obsidian 中都可以生效啦,而且Obsidian 中的图也可以正确生成咯~ 最终的结果就是上面那个图啦
由于我们的 permalink
中没有加上 output_ext
,因此解析后的 url
不会带有文件名后缀,所以在 Markdown 的链接中也不需要加上后缀。
在 Obsidian 中,我们也是可以通过点击 Markdown 的链接跳转到对应文章的,不过这要求我们的链接末尾不能有斜杠 /
,否则 Obsidian 会认为这是一个文件夹而非文件,导致跳转失败。
而 Jekyll 解析后的 url
末尾会补一个斜杠,这里需要注意,复制 url
之后记得要把斜杠删掉。
文件名:2022-02-03-XXX.md
Markdown链接:[Jump to XXX](../2022-02-03-XXX)
点击跳转后的URL:https://blackdn.github.io/2022-02-03-XXX/
通过文章锚点跳转
在 url
中,井号 #
作为定位符,因此我们可以在 url
的尾部通过 #xxx
来快速定位到页面的某个位置,这种定位称之为HTML锚点。
而 Jekyll 帮我们生成页面的时候,将 Markdown 的每个标题都作为锚点。当我们的鼠标放在标题上,旁边会出现一个链接符号,点击链接符号就会定位到这个标题的位置。
同理,如果我们在其他页面点击带有锚点的链接,会直接定位到锚点位置,而不是文章开头。
url编码 和 尾部斜杠
或许对某些人来说,url
中出现中文是一件很难受的事情,因此实际上我们可以对锚点内容进行url编码,空格会自然而然被编码成%20
,所以不用管他。
但是如果懒得编码,我们也可以保留原本内容,如上图所示,但是要注意以下两点:
- 英文字母全小写
- 空格用连接符
-
代替
(可能某些冷门的或者版本较低的浏览器不支持中文,但我就不考虑这么多了,反正我试了 Google 和 Safari 都是可以的)
此外,虽然上面的 url
中,锚点与前面的内容之间有一个斜杠/
(...-2024/#angular-js-简介
),但我们在 Markdown 中需要把这个斜杠去掉,原因和上面类似, Obsidian 会认为这是一个文件夹而非文件,导致跳转失败。
不过要注意一点,如果标题中间含有空格,比如这个...-2024/#angular-js-简介
的标题 Angular JS 简介,它在网页上可以成功定位锚点,在 Obsidian 中则会失败。(如果没有空格两那都能成功定位)
不过没事,它不妨碍 Obsidian 跳转到对应文章以及图的生成,只能说咱的 Obsidian 还有待加强🐶
标签页的锚点跳转
啥意思呢,就是我们的标签页(https://blackdn.github.io/tags/),里面可以点击对应标签进行跳转,实际上也是通过锚点实现的。
如果某些时候我们想从文章中跳转到这标签页的某个锚点,又不想在 Obsidian 的图中生成这个标签的点,可以像这样写 Markdown 的链接:
[Web]({{ site.baseurl }}/tags#Web)
可以点击试一下:跳转到Web标签
{{ site.baseurl }}
是 Jekyll 提供的语法,site.baseurl
是其配置的变量,在这里是 blackdn.github.io
。其他规则(编码啊啥的)都和上面一样
总之,这样既可以跳转到对应标签位置,又不会让这个标签页的锚点出现在 Obsidian 的图中
总的来说,为了实现 Jekyll 生成的 GitHub Pages 和 Obsidian 都可以通过相对路径实现文章间的跳转,需要经过以下几个步骤和约束:
- 在
_config.yml
文件中,修改项目的配置:permalink: /:year-:month-:day-:title/
- Markdown 链接中,先回到上级目录,采用
../2022-02-03-XXX
的形式(使得在网站中能够跳转) - Markdown 链接中,文件名尾部不需要斜杠(使得在 Obsidian 中能够跳转,能生成图)
- 若使用锚点,Markdown 链接中的锚点与文件名之间不需要斜杠(使得在 Obsidian 中能够跳转)
- 若使用锚点,Markdown 链接中的锚点内容用不用编码都可以。若不进行编码,则英文字母需要全小写,空格需要用连接符
-
代替 - 如果想从文章中跳转到标签页,Markdown 链接中需要按照
[Web]({{ site.baseurl }}/tags#Web)
的形式
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK