Jekyll Build Speed Up!
종종 제 Github page는 빌드가 실패합니다. 물론 대략적인 이유는 알고 있었습니다. Github page는 약 최대 13분 전후 정도의 build time을 가질 수 있는데, 이를 넘어가게 되면 pending 되거나 실패합니다. 제 Jekyll의 빌드 시간이 15분 정도 걸리던 상태로 당연히 실패하는 경우가 발생했었죠.
이는 Github Page에서 Jekyll 사용 시 자동 빌드 기능을 제공하는데, 해당 기능에서만 제한이 있습니다. 별도로 Github action으로 구성하시만 빌드 Limit이 길기 때문에 크게 걱정은 없을 것 같습니다.
그래서 오늘은 제가 Jekyll 빌드 속도를 올릴 수 있는 방법들에 대해 이야기하려고 합니다.
Analysis #
우선 빌드에 어떤 부분이 가장 많이 소요되고 있는지 찾아야 합니다. Jekyll은 build 시 --profile
이란 옵션을 통해 각 파일에 대한 빌드 소요시간을 알 수 있습니다.
bundle exec jekyll serve --profile
Filename | Count | Bytes | Time
--------------------------------+-------+------------+--------
_layouts/default.html | 790 | 131322.55K | 405.412
_includes/navigation.html | 790 | 61779.70K | 266.733
_includes/header.html | 790 | 42560.48K | 179.197
_includes/head.html | 790 | 52723.54K | 136.753
_includes/footer.html | 790 | 22425.51K | 88.645
_layouts/post.html | 649 | 8993.10K | 1.292
_includes/article-content.html | 113 | 2383.00K | 0.637
sitemap.xml | 1 | 95.25K | 0.518
_layouts/tag_page.html | 40 | 1630.02K | 0.453
_includes/social-links.html | 790 | 729.82K | 0.187
_includes/javascripts.html | 790 | 369.82K | 0.168
_layouts/redirect.html | 633 | 380.09K | 0.080
_includes/google-analytics.html | 790 | 318.62K | 0.074
_pages/archive.html | 1 | 133.15K | 0.066
search.json | 1 | 178.49K | 0.031
_includes/main.scss | 790 | 2453.32K | 0.03
....
그러면 어떤 부분에서 시간을 많이 잡아먹는지 알 수 있습니다.
My case #
제 경우에는 의외로 navigation 쪽에서 큰 오버헤드가 발생했었는데, 이는 Liquid의 무분별한 사용으로 인해 발생한 문제였습니다. Liquid 문법이 페이지를 만들기 쉽고 편리하기 때문에 자주 사용되지만, 만약 빌드 되어야하는 파일이 많다면 이는 반대로 속도에 큰 영향을 줄 수 있습니다.
기존 코드를 보면 네비게이션(메뉴)을 위해서 모든 Post에 모든 Page의 이름을 읽어와서 넣어주는 로직이 있었느데, 이는 다시 말해 1,000개의 포스트가 있다면 1,000 x page의 갯수
만큼의 루프를 발생시켰었습니다. 굉장하죠 😮
<ul class="nav__list list-reset">
{% for page in site.pages %}
{% unless page.name == 'tags.html' or page.name == '404.html' %}
{% if page.show != 'none' %}
{% if page.title %}
<li class="nav__item">
<a href="{{ page.url | prepend: site.baseurl }}" class="nav__link">{{ page.title }}</a>
</li>
{% endif %}
{% endif %}
{% endunless %}
{% endfor %}
</ul>
그래서 아래와 같이 고정 데이터로 수정하엿습니다.
<ul class="nav__list list-reset">
<li class="nav__item"><a href="/about/" class="nav__link">About</a></li>
<li class="nav__item"><a href="/archive/" class="nav__link">Archive</a></li>
<li class="nav__item"><a href="/cullinan/" class="nav__link">Cullinan</a></li>
<li class="nav__item"><a href="/phoenix/" class="nav__link">Phoenix</a></li>
<li class="nav__item"><a href="/resources/" class="nav__link">Resources</a></li>
</ul>
덕분에 결과는 엄청났죠 :D
_layouts/default.html | 791 | 70615.56K | 149.066
_includes/head.html | 791 | 52790.21K | 147.258
_layouts/post.html | 650 | 9000.80K | 1.366
_includes/article-content.html | 113 | 2386.38K | 0.640
_includes/footer.html | 791 | 2164.44K | 0.602
_layouts/tag_page.html | 40 | 1632.33K | 0.452
sitemap.xml | 1 | 95.39K | 0.443
_includes/header.html | 791 | 2035.43K | 0.389
_includes/javascripts.html | 791 | 370.28K | 0.183
기존: 405+266+179+137+88 = 1075
현재: 149+147 = 296
결국 1075
- 296
으로 779
초의 시간이 절약됬습니다. 대략 10분이 넘는 시간이네요. 페이지 정상 노출되는지 테스트하고, github page에 반영해봤는데, 기존에 커트라인에 걸쳐있던 빌드타임이 5분 내로 끝나는 안정적인 모습이 되었습니다.
Speed-Up Tips #
Optimize Liquid #
제 사례를 보면 아시겠지만, 잘못된 로직의 Liquid는 빌드 타임을 굉장히 늘릴 수 있습니다. 그래서 이를 분석하고 줄여나가는 과정을 통해 좀 더 빠르게 만들 수 있습니다. 굳이 불필요한 반복문 등은 줄이고 Static하게 직접 찍어주는 형태로 전환하면 사이트의 구성에 따라 큰 효과를 얻을 수도 있습니다
추가로 liquid-c
Gem도 있습니다. Liquid 문법의 처리를 C로 처리하면서 조금 더 속도를 올릴 수 있다고 하네요. 적용은 Gemfile에 liquid-c를 명시해준 후 패키지 설치(bundle install
) 이후 빌드하시면 됩니다.
gem 'liquid-c'
Using Github Action #
Github Page 배포의 기본 빌드는 Jekyll의 기본 옵션을 사용하여 빌드합니다. 그래서 모든 페이지를 빌드하기 때문에 속도가 느릴 수도 있습니다. 만약 속도가 문제가 되었다면 기본 Github page 기능으로 빌드하지 않고 jekyll-action 등의 Github action을 통해 빌드하는 것이 좋습니다.
Limit이 매우 큰 것도 좋지만, Action 자체에서도 캐싱을 사용하여 빌드 속도를 줄여주기 때문에 기본 빌드보다는 확실히 빠릅니다.
name: Deploy Job
on:
push
jobs:
jekyll:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- uses: actions/cache@v2
with:
path: vendor/bundle
key: ${{ runner.os }}-gems-${{ hashFiles('**/Gemfile') }}
restore-keys: |
${{ runner.os }}-gems-
- uses: helaili/jekyll-action@v2
with:
token: ${{ secrets.GITHUB_TOKEN }}
Include Cached #
jekyll-include-cache란 Gem을 통해 재 빌드가 불필요한 파일을 캐시하도록 명시할 수 있습니다.
gem `jekyll-include-cache`
위와 같이 Gemfile에 명시한 후 include 시 캐시가 필요한 부분(수정되지 않을 구간들)은 아래와 같이 include_cached
로 include 하면 좀 캐시하여 매번 새로 빌드하지 않게 됩니다.
{% include_cached header.html %}
Flags #
limit_posts #
jekyll 빌드 또는 serve 시 --limit_posts
플래그를 사용하면 posts의 갯수 제한을 걸어 빌드할 수 있습니다. 지정한 수 만큼의 최신 글만 볼 수 있기 때문에 로컬에서 글을 작성하고 실시간으로 결과를 확인할 때 유용합니다. (굳이 불필요한 파일까지 빌드할 필요가 없으니깐요)
bundle exec jekyll serve --limit_posts=10
incremental #
jekyll 빌드 또는 serve 시 --incremental
플래그를 사용하면 변화가 있는 페이지만 리빌드하게 됩니다.
bundle exec jekyll serve --incremental