Initially I was going to title this article Hacking a routing component in Jekyll when hosted on GitHub Pages with Markdown, Liquid, and YAML. Obviously, that’s a bit long so I had to shorten it. Anyway, the point doesn’t change: Jekyll lacks some kind of router, and I think I found a not-so-terrible solution to mimic one.
最初,我要为这篇文章加上标题,当使用Markdown,Liquid和YAML托管在GitHub Pages上时,会在Jekyll中入侵路由组件 。 显然,那有点长,所以我不得不缩短它。 无论如何,关键点并没有改变: Jekyll缺少某种路由器,我想我找到了一个不太可怕的解决方案来模仿它。
But first things first: I come from a Symfony background, so by router I mean a component that maps URLs to names — a.k.a. routes – so you can safely change a URL without having to crawl your codebase to update all the links heading to the obsolete location.
但是首先要考虑的是:我来自Symfony的背景,所以路由器是指将URL映射到名称(也称为路由)的组件,因此您可以安全地更改URL,而不必抓取代码库来更新所有过时的链接。位置。
为什么我们需要这样的东西? (Why would we need such a thing?)
I am currently working hard on the docs for SassDoc v2 (not released yet, as of this writing). We have quite a bit of content; over 20 pages split across 4 different sections containing many code examples and cross references.
我目前正在努力研究SassDoc v2的文档(在撰写本文时尚未发布)。 我们有很多内容; 超过20页,分为4个不同的部分,其中包含许多代码示例和交叉引用。
A couple of times during the rewriting, I desired to change a URL. Problem is, when I change a URL I have to update all the links heading to this URL if I don’t want them to be broken. Crawling over 20 pages to make sure all URLs are alright is far from ideal…
在重写过程中,有几次我想更改一个URL。 问题是,当我更改URL时,如果我不希望它们断开,则必须更新指向该URL的所有链接。 爬网超过20页以确保所有URL都正常,这远非理想……
This is why we need a routing component. Then we would refer to URLs by name rather than by their path, allowing us to change a path while keeping the name perfectly valid.
这就是为什么我们需要一个路由组件。 然后,我们将通过名称而不是通过路径来引用URL,从而使我们能够在保持名称完全有效的同时更改路径。
它是如何工作的? (How does it work?)
So what do we need to make this work? If you are running Jekyll but are not restricted to safe mode (which is unfortunately the case when using GitHub Pages for hosting), you can surely find/build a Ruby plugin to do this. This would be the best solution since this is typically something handled by a server-side language.
那么,我们需要做些什么呢? 如果您正在运行Jekyll,但不限于安全模式(不幸的是,使用GitHub Pages进行托管的情况),则可以肯定地找到/构建一个Ruby插件来执行此操作。 这将是最好的解决方案,因为这通常是由服务器端语言处理的。
Now, if you host your site on GitHub Pages which is more often the case than not with Jekyll, you cannot use plugins nor can you extend Jekyll’s core with custom Ruby code, so you end up hacking a solution with what’s available: Liquid and Markdown.
现在,如果您将站点托管在GitHub Pages上(而不是使用Jekyll),您将无法使用插件,也无法使用自定义Ruby代码扩展Jekyll的核心,因此您最终会破解一个可用的解决方案: Liquid和Markdown 。
The main idea is to have a file containing all our routes mapped to actual URLs. Thankfully, Jekyll allows us to define custom global variables through YAML/JSON/CSV files stored in the _data
folder, later accessed via site.data.<filename>
. Thus we can access those URLs directly in our pages from their name.
主要思想是要有一个包含我们所有映射到实际URL的路由的文件。 值得庆幸的是,杰基尔允许我们定义通过YAML / JSON / CSV自定义的全局变量文件存储在_data
文件夹中,之后通过访问site.data.<filename>
。 因此,我们可以直接从页面名称中访问这些URL。
To add a little syntactic sugar on top, we’ll create Markdown link references that will allow a friendlier syntax – but let’s not go too fast too quickly.
为了在语法上加点糖,我们将创建Markdown链接引用,该引用将允许使用更友好的语法–但是我们不要太快。
创建路由器 (Creating the router)
The point of the router is to expose routes (a.k.a. names) mapped to URLs (one to one). It is possible to create YAML/JSON/CSV files in the _data
folder of any Jekyll project, so let’s go with a YAML file named routes.yml
:
路由器的一点是揭露映射到URL(一对一)的路线(又名名 )。 它可以创建YAML / JSON /在CSV文件_data
任何化身项目的文件夹,让我们有一个名为YAML文件去routes.yml
:
home: "/"
about: "/about-us/"
faq: "/frequently-asked-questions/"
repository: "https://github.com/user/repository"
You may have noted that we are of course not restricted to internal links. We can totally define routes for external URLs to avoid typing them again and again if they tend to show up regularly. Along the same lines, we stopped at 4 routes for our example, but the router could contain hundreds of routes.
您可能已经注意到,我们当然不限于内部链接。 我们可以完全定义外部URL的路由,以避免在它们经常出现的情况下避免一次又一次地键入它们。 同样,在本例中,我们在4条路由处停了下来,但路由器可能包含数百条路由。
Because the file is in _data
, we can access its content pretty much anywhere with site.data.<filename>.<key>
. So let’s say we have a page containing the following code:
由于该文件位于_data
,因此我们可以使用site.data.<filename>.<key>
几乎在任何地方访问其内容。 假设我们有一个包含以下代码的页面:
---
layout: default
title: "About us"
---
<!-- Content about us -->
Go to our [GitHub repository]({{ site.data.routes.repository }}).
Or read the section dedicated to [Frequently Asked Questions]({{ site.data.routes.faq }}).
As you can see, we no longer refer to URLs, but routes instead. This is not magic, it only tells Jekyll to access global variables stored at the given path (e.g. site.data.routes.faq
).
如您所见,我们不再引用URL,而是引用路由。 这不是魔术,它只是告诉Jekyll访问存储在给定路径中的全局变量(例如site.data.routes.faq
)。
Now, if the repository is no longer hosted on GitHub or the “About us” page’s URL is now /about/
, not to worry! By updating the router, we make it work without having to come back to our pages to update our links.
现在,如果存储库不再托管在GitHub上,或者“关于我们”页面的URL现在是/about/
,请不用担心! 通过更新路由器,我们可以使其工作而无需返回页面来更新我们的链接。
添加语法糖 (Adding syntactic sugar)
At this point, we have a functional router allowing us to change any URL without having to crawl our site to fix broken links. So you can say it is pretty cool already. However, having to type site.data.routes.faq
is not very convenient. We could surely make it a bit more elegant!
至此,我们有了一个功能强大的路由器,允许我们更改任何URL,而无需爬网我们的站点来修复断开的链接。 所以您可以说它已经很酷了。 但是,必须键入site.data.routes.faq
并不是很方便。 我们一定可以使其更加优雅!
Yes and no. At first, I thought of building a small route()
function accepting a key name and returning the value stored at site.data.routes.<key>
. The problem is we are running Jekyll in safe mode, so we cannot extend it with Ruby code. No luck.
是的,没有。 起初,我想到了构建一个小的route()
函数来接受键名并返回存储在site.data.routes.<key>
。 问题是我们在安全模式下运行Jekyll,因此我们无法使用Ruby代码对其进行扩展。 没运气。
Then I thought of a Markdown feature I never used before: link references. This is how a link is represented in Markdown:
然后,我想到了一个我从未使用过的Markdown功能: 链接引用 。 这是Markdown中链接的表示方式:
[I am a link](http://link.url/)
You can also set the link to head to a reference — which is completely invisible by the way, defined anywhere in the page, like so:
您还可以将链接设置为指向引用的头,该引用在页面的任何位置都完全不可见,如下所示:
[I am a link][id_reference]
[id_reference]: http://link.url
Note: parentheses are replaced with brackets when using a reference rather than a URL.
注意:使用参考而非URL时,括号将替换为括号。
This could allow you to have all your links defined in the same place (at the bottom for instance) rather than all over the document. I must say I haven’t used this feature much, but in this case it comes in handy.
这可以让您将所有链接定义在同一位置(例如,在底部),而不是整个文档。 我必须说我没有太多使用此功能,但是在这种情况下它很方便。
The idea is to autogenerate link references from our router so we can use our routes as reference in any file. It turns out to be surprisingly easy to do this in Liquid:
这个想法是从路由器自动生成链接引用,以便我们可以将路由用作任何文件中的引用。 事实证明,在Liquid中执行此操作非常容易:
# _includes/route.html
{% for route in site.data.routes %}
[{{ route[0] }}]: {{ route[1] }}
{% endfor %}
By adding this for loop anywhere in the page, this instructs Jekyll to process this as Liquid code, which will then be processed as Markdown references. So for instance, and coming back to our previous example, we could do:
通过在页面中的任何位置添加此for循环,这指示Jekyll将其作为Liquid代码进行处理,然后将其作为Markdown引用进行处理。 因此,例如,回到前面的示例,我们可以执行以下操作:
---
layout: default
title: "About us"
---
<!-- Content about us -->
Go to our [GitHub repository][repository].
Or read the section dedicated to [Frequently Asked Questions][faq].
{% for route in site.data.routes %}
[{{ route[0] }}]: {{ route[1] }}
{% endfor %}
Now we’re talking, right? The only problem is having to include this loop in any page. At first, I thought of adding it in the layout, so it gets automatically added to any page using the relevant layout. The problem is that layouts are not processed as Markdown in Jekyll so the references actually come in visible at the bottom of the DOM. Even worse, they are not usable in our pages since they have not been processed as Markdown… Too bad.
现在我们在说话,对吗? 唯一的问题是必须在任何页面中包含此循环。 最初,我考虑过将其添加到布局中,因此可以使用相关布局将其自动添加到任何页面。 问题在于布局在Jekyll中没有像Markdown一样处理,因此引用实际上在DOM的底部可见。 更糟糕的是,由于无法将它们作为Markdown处理,因此无法在我们的页面中使用。
However we can still do something to make it slightly better. We can put this loop in a Liquid partial and include the partial in every page rather than copy-pasting the loop. Say we create a routes.html
partial in the _includes
folder:
但是,我们仍然可以做一些改进。 我们可以将此循环放在Liquid局部中,并在每个页面中包含该局部,而不是复制粘贴循环。 假设我们在_includes
文件夹中创建了一个routes.html
部分:
{% for route in site.data.routes %}
[{{ route[0] }}]: {{ route[1] }}
{% endfor %}
And then, in our page:
然后,在我们的页面中:
---
layout: default
title: "About us"
---
{% include routes.html %}
<!-- Content about us -->
Go to our [GitHub repository][repository].
Or read the section dedicated to [Frequently Asked Questions][faq].
Note: you can include the partial anywhere in the page, not only on top. You could totally put it as the very last line of the file.
注意:您可以在页面中的任何地方(不仅在顶部)包括部分内容。 您完全可以将其作为文件的最后一行。
最后的想法 (Final thoughts)
That’s it folks, we’ve hacked a little routing component in Jekyll safe-mode. Now what are the drawbacks of this? There are a few minor ones:
就是这样,伙计们,我们在Jekyll安全模式下入侵了一个小的路由组件。 现在这有什么弊端? 有一些较小的:
It works in Markdown; if you happen to have a link in plain HTML, you have to fall back to
{{ site.data.routes.<key> }}
, which is not too bad since it still keeps links safe from URL updates.它可以在Markdown中工作; 如果您碰巧有纯HTML链接,则必须退回到
{{ site.data.routes.<key> }}
,因为它仍然可以确保链接不受URL更新的影响,所以还算不错。You cannot add an anchor to the link; if you need to, fall back to
{{ site.data.routes.<key> }}#anchor
(again, not too bad).您无法将锚添加到链接; 如果需要,请退回到
{{ site.data.routes.<key> }}#anchor
(同样,也不错)。- You have to include the HTML partial in all pages, which can be tedious (even if you consider this as an extension of the YAML front matter you have to write anyway). 您必须在所有页面中包括HTML部分,这可能很乏味(即使您将其视为YAML前端问题的扩展,也无论如何都必须编写)。
Aside from those drawbacks, it’s all good and shiny. What do you think?
除了这些缺点之外,这些都是好东西和闪亮的东西。 你怎么看?
翻译自: https://www.sitepoint.com/hacking-routing-component-jekyll/