Hugo: 정적 사이트 생성기
원문은 Ben Hoyt님이 에 게재했습니다. 이 블로그 구독하기
정적 웹사이트 생성기는 마크업 언어로 작성된 페이지 콘텐츠를 완전히 렌더링된 HTML로 변환해 개발자가 결과물을 업로드하여 웹사이트를 간단하고 안전하게 서비스할 수 있게 해준다. 이 글에서는 Go로 작성되어 속도에 최적화된 정적 사이트 생성기인 Hugo를 살펴본다. Hugo는 단순한 블로그부터 프로젝트 문서, 대규모 뉴스 사이트, 심지어 정부 서비스에 이르기까지 다양한 용도로 구성할 수 있는 유연한 도구다.
배경
정적 사이트 생성기는 아마 HTML이 발명된 때부터 존재했을 것이다. 대부분의 사이트는 공통 헤더와 푸터를 가지고 있고, 사이트 운영자는 이를 모든 페이지에 일일이 복사해 붙여 넣고 싶어 하지 않는다. 당시 개발자들은 HTML을 이어 붙이기 위해 수십 줄 정도의 맞춤형 Perl이나 Bash 스크립트를 작성하곤 했다. 그 방법도 분명 동작은 하지만, 오늘날의 정적 사이트 생성기는 단순한 커스텀 스크립트보다 훨씬 빠르고 강력하다.
많은 사이트는 공통 헤더 등을 페이지 조회마다 동적으로 렌더링하는 방식으로 처리한다. 예를 들어 데이터베이스에 연결된 PHP를 사용하는 식이다. 2020년이라면 개발자들은 콘텐츠를 제공하는 HTTP API에 연결된 React 프론트엔드를 사용할 가능성이 더 높을 것이다. 하지만 사이트가 대체로 정적인 콘텐츠만 제공하면 되는 경우, 이 두 가지 방식은 모두 과도하다.
많은 개인 사이트와 블로그, 그리고 프로젝트 및 기업 문서 사이트는 정적으로 생성할 수 있다. 미리 렌더링된 HTML을 제공하는 것이 동적으로 렌더링된 콘텐츠를 제공하는 것보다 빠르고 안정적이다. 위키백과에서는 정적 웹사이트가 제공하는 몇 가지 장점을 다음과 같이 나열한다:
- 동적 웹사이트 대비 향상된 보안(취약점이 있을 경우 동적 웹사이트는 웹 셸 공격에 노출될 위험이 있다)
- 동적 웹사이트 대비 최종 사용자를 위한 향상된 성능
- 데이터베이스나 기타 애플리케이션 서버와 같은 시스템에 대한 의존성이 적거나 전혀 없음
물론 일부 웹사이트(특히 웹 애플리케이션)는 항상 동적 콘텐츠를 필요로 한다. 기사 내용이 정적인 LWN조차도 로그인한 구독자와 로그인하지 않은 방문자에게 서로 다른 콘텐츠를 제공해야 한다. 따라서 동적 서버와 API에 대한 수요는 항상 존재할 것이다. 하지만 사이트 콘텐츠가 정적이고 공개되어 있거나, 동적 콘텐츠를 클라이언트 측에서 처리할 수 있는 경우에는 정적 사이트 생성기가 시스템을 크게 단순화할 수 있다.
정적 사이트 생성기는 비교적 만들기 쉽기 때문에 다양한 오픈소스 옵션이 존재한다. 주요 프로그래밍 언어마다 꽤 인기 있는 제품이 있는데, 예를 들면 Ruby의 Jekyll, Python의 Pelican, Java의 JBake, PHP의 Sculpin, JavaScript의 Hexo 등 수백 가지가 더 있다. 여기서는 활발하게 유지보수되고 있는 오픈소스 프로젝트인 Hugo를 살펴본다.
Hugo는 2013년 Steve Francia(현재 Go 핵심 팀원)에 의해 만들어졌지만, 2015년부터는 Bjørn Erik Pedersen이 리드 개발자를 맡았다. 이 프로젝트는 GitHub에 호스팅되어 있으며, 현재 주석을 제외하고 약 43,000줄의 Go 소스 코드로 이루어져 있고 관대한 Apache License 2.0으로 배포된다. 물론 Hugo로 만든 탄탄한 문서 사이트도 갖추고 있다. 또한 비교적 트래픽이 많은 토론 포럼과 수많은 사용자가 제출한 테마를 통해 커뮤니티 참여도 활발하다. Pedersen은 2017년에 Hugo의 인프라(개발 제외)에는 일부 기업 후원이 있다고 말한 바 있다. “Netlify가 우리 사이트를 무료로 호스팅해주고, Discourse가 포럼을 운영해줍니다. 빌드는 Travis, Appveyor, CircleCI를 사용합니다. 그 외에는 후원사가 없습니다.
”
사이트 생성기가 어떤 프로그래밍 언어로 작성되었는지는 그리 중요하지 않다(필자 개인적으로는 Jekyll을 사용하지만 Ruby를 직접 작성할 필요는 없었다). 다만 개발자들은 대체로 자신이 익숙한 언어로 만들어진 도구를 선호하는 경향이 있다. Hugo를 사용하더라도 Go를 직접 작성해야 할 일은 거의 없겠지만, 테마를 직접 만들거나 커스터마이징한다면 Go의 HTML 템플릿 문법을 다룰 필요가 있을 수 있다.
BuiltWith에 따르면, Hugo 사용량은 지난 3년간 급격히 증가했다. 새롭게 디자인된 Smashing Magazine 사이트, 1Password 지원 사이트와 블로그, Let's Encrypt 웹사이트, 그리고 미국 정부의 Digital.gov 사이트 등 여러 유명 프로젝트에서 사용되고 있다.
작동 방식
옵션 없이 실행하면, hugo는 content 하위 디렉터리에 있는 Markdown 파일을 순회하며 렌더링된 HTML을 public이라는 하위 디렉터리에 출력한다. 이 모든 것은 설정 가능하며, 기본 설정 파일은 프로젝트 루트에 있는 config.toml이다. 출력물은 테마에 따라 렌더링되는데, 테마는 정확히 어떤 HTML이 생성될지를 정의하는 몇 개의 Go HTML 템플릿 모음이다. 테마에는 CSS 스타일은 물론 테마에 필요한 이미지나 JavaScript 파일도 포함된다.
이 글을 쓰기 전에 필자는 세 개의 글과 “About” 페이지로 구성된 간단한 테스트 사이트를 만들었다. 개인 웹사이트나 블로그에 쓸 법한 구성이다. 테마를 고르고 Hugo를 설정한 뒤 더미 콘텐츠를 추가하는 데 약 30분이 걸렸다. Hugo는 주요 운영체제 패키지 관리자나 GitHub의 프리빌드 바이너리(Linux, 각종 BSD, macOS, Windows용), 또는 소스 빌드를 통해 설치할 수 있다. Hugo의 경우 소스 빌드는 Go를 설치하고(아직 설치되어 있지 않다면) 프로젝트를 클론한 뒤 go build를 입력하는 것만큼 간단하다. 필자의 머신에서는 클론부터 “hugo version” 실행까지 약 20초가 걸렸다.
개발 중에는 “hugo server”를 입력하면 렌더링된 콘텐츠를 RAM에서 서비스하는 로컬 웹 서버가 시작된다. 이 모드에서는 Hugo가 파일을 자동으로 감시하고 필요에 따라 HTML을 다시 빌드한다. 렌더링된 페이지에는 해당 콘텐츠가 변경되는 즉시 웹 브라우저에서 자동으로 새로고침되도록 하는 JavaScript 코드까지 포함되어 있다(웹 소켓을 이용한 LiveReload 사용). Hugo의 내장 서버는 프로덕션 수준의 net/http 서버를 기반으로 하지만, 배포 시에는 렌더링된 파일을 미리 빌드해 Amazon S3 같은 정적 사이트 호스트에 업로드하거나 NGINX 같은 일반 웹 서버 뒤에서 서비스하는 것이 보통 더 간단하다.
다른 정적 사이트 생성기와 마찬가지로, Hugo는 페이지에 YAML 형식의 “front matter”와 Markdown 콘텐츠를 “---” 줄로 구분하는 단순한 파일 형식을 사용한다. 다음은 예제 사이트의 첫 번째 글의 내용이다:
--- title: "First Post" date: 2020-07-06T09:33:48+12:00 categories: - Development --- The quick brown fox jumps over the lazy dog. Ee equals em cee squared. Let's try a [link](https://benhoyt.com/) and **some bold text**. Another paragraph. Hugo seems to be working. Writing Markdown is nice.
Hugo 테마 템플릿이 어떻게 생겼는지 감을 잡을 수 있도록, 테스트에 사용한 Soho 테마에 포함된 single.html 템플릿을 소개한다(단일 블로그 글을 렌더링한다):
{{ define "main" -}}
<div class="post">
<h1>{{ .Title }}</h1>
{{ if ne .Type "page" -}}
<div class="post-date">
<time datetime="{{ .Date.Format "2006-01-02T15:04:05Z0700" }}">
{{ .Date.Format "Jan 2, 2006" }}
</time>
· {{ .ReadingTime }} min read
</div>
{{- end }}
{{ .Content }}
</div>
{{- end }}Hugo는 페이지를 분류하는 다양한 방법인 “taxonomies”를 지원하며, 각 taxonomy마다 해당 taxonomy가 지정된 모든 글을 나열하는 페이지를 생성한다. 기본적으로 “tags”와 “categories” taxonomy를 생성하는데, 예를 들어 테스트 사이트의 “Development” 카테고리가 그렇다. 문서에서는 taxonomy를 정렬하거나 메타데이터를 추가하는 다양한 방법을 소개한다.
이 도구는 렌더링된 콘텐츠에서 페이지 URL(“permalinks”)을 제어하는 다양한 방법을 지원하며, 기본값인 /:section/:filename/은 /posts/third-article/ 같은 URL을 생성한다. :section 이름은 content 내 하위 디렉터리 이름(예: posts)에서 오고, :filename은 확장자를 제외한 콘텐츠 파일의 이름이다. 이러한 “directory URL”은 렌더링된 HTML 파일을 인덱스 파일과 함께 디렉터리에 생성하는 방식으로 구현된다: /posts/third-article/index.html.
Hugo의 좀 더 고급 기능 중 하나는 “shortcodes”라고 불리는 것으로, Markdown의 제한적인 기능을 HTML로 직접 대체하지 않고도 보완할 수 있게 해주는 파라미터가 포함된 작은 HTML 조각이다. gist(GitHub Gist 포함), highlight(구문 강조 코드), youtube(인라인 YouTube 동영상) 등 다양한 내장 shortcode가 있다. 예를 들어 다음 shortcode는:
{{< youtube w7Ft2ymGmfc >}}다음과 같은 HTML 출력을 생성한다:
<div style="position: relative; padding-bottom: 56.25%; height: 0; overflow: hidden;">
<iframe src="https://www.youtube.com/embed/w7Ft2ymGmfc?autoplay=1"
style="position: absolute; top: 0; left: 0; width: 100%; height: 100%; border:0;"
allowfullscreen title="YouTube Video"></iframe>
</div>Hugo에는 글 안의 제목으로부터 목차를 생성하는 기능, 대체 마크업 형식(Markdown이 기본값이다), CSS와 JavaScript를 전처리하기 위한 파이프라인, 이미지를 크기 조정하고 자르기 위한 이미지 처리 명령 등 더 고급 기능도 포함되어 있다.
Hugo는 속도가 빠르다고 알려져 있으며, 홈페이지에서는 “페이지당 <1 ms로, 평균적인 사이트는 1초 이내에 빌드된다
”고 소개한다. Smashing Magazine의 7,500페이지짜리 사이트는 약 13초 만에 빌드된 것으로 전해진다. 이러한 속도는 부분적으로는 네이티브 바이너리로 컴파일되는 언어인 Go로 작성되었기 때문이지만(Python 같은 바이트코드 인터프리터 언어와 달리), 수년에 걸쳐 기여자들이 기울인 다양한 벤치마킹 및 성능 개선 노력 덕분이기도 하다. 예를 들어 2020년 1월에 출시된 버전 0.63의 릴리스 노트를 참고하면 된다.
일반적으로 정적 사이트 생성기를 사용할 때는 콘텐츠 작성자가 개발자이거나 최소한 텍스트 에디터, Markdown, Git 사용에 익숙해야 한다. 하지만 웹 호스트인 Netlify는 비개발자도 WYSIWYG 에디터를 사용해 기여할 수 있게 해주는 Netlify CMS라는 오픈소스 도구를 제공한다. 이 도구는 뒤에서 Git 저장소에 커밋한다. Hugo 문서에는 다른 유사한 도구들의 목록이 있다.
호스팅 옵션
정적 사이트 생성 방식을 사용하면 개발자는 렌더링된 결과물을 어떤 호스트나 웹 서버에서든 호스팅할 수 있다. 인기 있는 옵션으로는 GitHub Pages, Amazon S3, Netlify, 또는 Caddy나 NGINX 웹 서버를 이용한 셀프 호스팅이 있다. Hugo는 다양한 옵션에 대한 자세한 설정 정보를 담은 문서 페이지를 제공한다.
테스트 사이트의 경우 필자는 Amazon S3(AWS의 Cloudfront CDN을 앞에 둔 구성)를 사용하기로 했다. 설정이 꽤 간단하며, 월 몇 달러만으로 수백만 건의 페이지 뷰를 처리할 수 있다. 물론 클라우드를 전혀 사용하지 않고 보유한 서버에 호스팅할 수도 있다. 저렴한 서버라도 초당 수천 건의 정적 파일 요청을 처리할 수 있다.
사이트의 Git 저장소에 커밋이 있을 때마다 Hugo 빌드를 실행하도록 지속적 통합(예: GitHub Actions)을 사용하는 것도 간단하며, 이를 통해 렌더링된 버전을 항상 최신 상태로 유지할 수 있다.
마무리
Hugo는 공개된 로드맵이나 고정된 릴리스 일정이 없어 보인다. 최근 몇 년간은 버그 수정 릴리스를 포함해 거의 매달 릴리스가 있었다. Pedersen은 2018년 7월에 “1.0으로 가는 길”에 대해 이야기한 바 있지만, 현재 유지보수자들은 0.x 버전 번호에 꽤 만족하는 것으로 보인다. 릴리스 이름은 종종 가벼운 느낌으로 붙여지는데, “Christmas Edition”이나 “40K GitHub Stars Edition” 같은 이름이 그 예이다.
정적 사이트 생성기는 대부분 정적인 콘텐츠로 구성된 웹사이트를 구축하고 배포하는 비교적 간단한 방법이다. Hugo의 속도와 관대한 라이선스, 다양한 기능은 작은 개인 웹사이트든 대규모 콘텐츠 중심 사이트든 개발자에게 매력적인 선택지가 된다. 전반적으로 Hugo는 주목할 만한 활발한 프로젝트다.
[이 주제를 제안해주신 Jim Garrison께 감사드립니다.]
글을 무작위로 읽기
댓글
로그인하고 댓글 남기기