GitHub Pages + Jekyll에 태그 달기

GitHub Pages에 내장된 JekyllGitHub Page gem에 포함된 플러그인만 지원한다.

지금 상황은 이렇다(테마 제외):

$ bundle exec github-pages versions
+------------------------------+---------+
| Gem                          | Version |
+------------------------------+---------+
| jekyll                       | 3.7.3   |
| jekyll-sass-converter        | 1.5.2   |
| kramdown                     | 1.16.2  |
| jekyll-commonmark-ghpages    | 0.1.5   |
| liquid                       | 4.0.0   |
| rouge                        | 2.2.1   |
| github-pages-health-check    | 1.4.0   |
| jekyll-redirect-from         | 0.13.0  |
| jekyll-sitemap               | 1.2.0   |
| jekyll-feed                  | 0.9.3   |
| jekyll-gist                  | 1.5.0   |
| jekyll-paginate              | 1.1.0   |
| jekyll-coffeescript          | 1.1.1   |
| jekyll-seo-tag               | 2.4.0   |
| jekyll-github-metadata       | 2.9.4   |
| jekyll-avatar                | 0.5.0   |
| jekyll-remote-theme          | 0.2.3   |
| jemoji                       | 0.9.0   |
| jekyll-mentions              | 1.3.0   |
| jekyll-relative-links        | 0.5.3   |
| jekyll-optional-front-matter | 0.3.0   |
| jekyll-readme-index          | 0.2.0   |
| jekyll-default-layout        | 0.1.4   |
| jekyll-titles-from-headings  | 0.5.1   |
| listen                       | 3.1.5   |
| activesupport                | 4.2.9   |
| minima                       | 2.4.0   |
| jekyll-swiss                 | 0.4.0   |
: ...                          : ...     :
+------------------------------+---------+

태깅 때문에 로컬에서 jekyll build하는 건 귀찮고, 직접 블로그 서버를 운영하는 건 더 귀찮고, 일반적인 블로그 서비스에 가입하는 건… 흠…

그래서, jekyll의 콜렉션 기능을 활용하여 플러그인없이 약간의 수작업(?)으로 태깅을 구현했다.

전역 콜렉션 & 기본값 설정

_config.yml 파일에 collections, defaults 설정을 추가

# ...
collections:
  tags:
    output: true
    permalink: /tags/:path/
# ...
defaults:
  - scope:
      path: ''
      type: tags
    values:
      layout: tag
# ...

포스트에 태그 추가하기

Front Mattertags 배열 추가

ex. 지금 보고 있는 이 포스트githubpages, jekyll, tags 태그 추가

---
title: GitHub Pages + Jekyll에 태그별 포스트 목록 지원하기
date: 2018-06-04
tags: [githubpages, jekyll, tags]
---
...

태그 정의 파일 추가

_tags 디렉토리를 만들고, 각 태그마다 태그 정의 파일을 하나씩 추가(이것이 앞에서 말한 약간의 수작업이다).

ex. _tags/life.md 파일 추가

---
name: life
---
...

새로운 태그가 등장할 때 마다 이런 뻔한 파일을 만들어야 한다.

태그별 포스트 목록 페이지 추가

_layouts/tag.html 파일 추가

---
layout: default
---
<ul id="post-list">
    {% for post in site.posts %}
        {% if post.tags contains page.name %}
            {% include item.html %}
        {% endif %}
    {% endfor %}
</ul>

결과는 https://your-site-url/tags/tag-name/에서 확인할 수 있다.

태그 전체 목록 페이지 추가

_layouts/tags.html 파일 추가

---
layout: default
---
<h1>Posts in "<em>{{ page.name }}</em>"</h1>
<ul class="post-list">
    {% for post in site.posts %}
    {% if post.tags contains page.name %}
    <li class="post-item">{% include post_item.html %}</li>
    {% endif %}
    {% endfor %}
</ul>

결과는 https://your-site-url/tags/에서 확인할 수 있다.

자동으로 태그 정의 파일 생성하기

여기까지는 내가 만들고 운영했던 GitHub Pages + Jekyll 기반 블로그들에서 썼던 방법 그대로다.

2년이 지났지만 딱히 GitHub Pages + Jekyll 의 상황은 별로 달라지지 않았고, 마침 딱히 할 일도 없어서… 간단한 스크립트를 몇 줄 짰다.

update_tags.py 파일 추가

import os
import re

for root, dirs, files in os.walk('_posts'):
    for file in files:
        if file.endswith('.md'):
            for line in open(os.path.join(root, file)).read().splitlines():
                m = re.match(r'^tags\s*:\s*\[(.+)\]\s*$', line)
                if m:
                    for tag in re.findall(r'\w+', m.group(1)):
                        try:
                            open('_tags/%s.md' % tag, 'x').write('---\nname: %s\n---\n' % tag)
                            print('create:', tag)
                        except:
                            print('skip:', tag)

파알못이 발로 짠거라… 길게 설명하고 싶지 않다. 그냥 실행하면, 태그 정의 파일이 있으면 건너뛰고(skip), 없으면 만든다(create).

python ./update_tags.py
create: githubpages
skip: jekyll
skip: tags
skip: githubpages
skip: https
skip: letsencrypt
skip: devops
create: life
...

이제 git push 하기 전에 이 스크립트를 한번씩 돌려주면 된다.

“이럴꺼면 그냥 jekyll build 하면 되는거 아니냐”고 물으신다면… 그러게 말입니다 Orz

That’s all Folks!