Heesung Yang

Hugo - 03. 템플릿 구조

서론

템플릿 구조를 이해하기 위해 이전에 설치했던 ananke 테마를 사용하지 않고 layouts 폴더에 html 템플릿 파일을 생성하며 하나하나 그 구조를 파헤쳐보자.

  • config.toml

    baseURL = "http://example.org/"
    languageCode = "en-us"
    title = "My New Hugo Site"
    # theme = "ananke"                 # << 삭제 (주석처리)
    

그리고 hugo server를 실행해보면, 아무것도 안나온다.

~$ hugo server -D

blank homepage

자, 이제 템플릿 구조를 파헤쳐보자.

List 템플릿

일단 layouts/_default/list.html 파일을 생성해보자. 생성 후 폴더 구조는 아래와 같다.

.
├── archetypes
│   └── default.md
├── config.toml
├── content
│   └── posts
│       └── first-post
│           ├── index.md
│           └── sample.png
├── data
├── layouts
│   └── _default
│       └── list.html     << 추가
├── resources
│   └── 생략...
├── static
└── themes
    └── ananke

list.html 파일을 아래와 같이 작성하자.

<!DOCTYPE html>
<html>
<head>
    <title>List Template</title>
</head>
<body>
    List Template

    <ul>
    {{ range .Pages }}
        <li><a href="{{ .URL }}">{{ .Title }}</a></li>
    {{ end }}
    </ul>
</body>
</html>

그리고 다시 hugo 서버를 실행해보면

list template

우리가 좀 전에 생성한 list.html 파일을 이용하여 html 페이지가 생성된 것을 확인할 수 있다. Posts 링크를 눌러보면 또 다시 First Post라는 링크가 있는 List 페이지가 나타난다.

posts list 1

이 상태에서 포스팅 2개를 추가로 작성해보자.

hugo new content/posts/second-post.md
hugo new content/posts/third-post.md

각 포스팅의 내용은 아래와 같이 간단하게 작성하자.

  • content/posts/second-post.md

    ---
    title: "Second Post"
    date: 2021-09-04T18:45:55+09:00
    draft: true
    ---
    
    This is the second post
    
  • content/posts/third-post.md

    ---
    title: "Third Post"
    date: 2021-09-04T18:46:00+09:00
    draft: true
    ---
    
    This is the third post
    

자, 이제 다시 Posts 페이지를 확인해보면 아래와 같이 각 포스팅의 제목이 보이는 것을 확인할 수 있다. (http://localhost:1313/posts/)

posts list 2

즉, list.html 파일은 작성된 포스팅 리스트를 표현하기 위해 사용하는 html 템플릿이다. 지금은 각 포스팅 제목을 클릭해보면 아무것도 나타나지 않는데 각 포스팅 내용이 나타나도록 single 템플릿을 추가해보자.

Single 템플릿

Single 템플릿은 바로 우리가 작성한 markdown 문서가 html로 변환될 때 사용하는 템플릿이다. 아래와 같이 layouts/_default/single.html 파일을 추가하자.

.
├── archetypes
│   └── default.md
├── config.toml
├── content
│   └── posts
│       ├── first-post
│       │   ├── index.md
│       │   └── sample.png
│       ├── second-post.md
│       └── third-post.md
├── data
├── layouts
│   └── _default
│       ├── list.html
│       └── single.html    << 추가
├── resources
│   └── 생략...
├── static
└── themes
    └── ananke
<!DOCTYPE html>
<html>
<head>
    <title>Single Template</title>
</head>
<body>
    Single Template

    <h1>{{ .Title }}</h1>

    <h6>{{ .Date }}</h6>

    <p>{{ .Content }}</p>
</body>
</html>

그리고 각 포스트 링크를 클릭해보면 아래와 같이 우리가 markdown으로 작성했던 내용이 잘 보인다.

post-1 post-2 post-3

이게 전부다. 중요하니까 3번 적는다.

Hugo에서 각 페이지는 List 타입 또는 Single 타입 이다.

Hugo에서 각 페이지는 List 타입 또는 Single 타입 이다.

Hugo에서 각 페이지는 List 타입 또는 Single 타입 이다.

List 타입의 페이지는

  • 블로그 접속 시 처음 보여주는 홈페이지
  • 포스팅 리스트 페이지
  • 포스팅마다 tag를 단 경우, 어떤 tag들이 있는지 보여주는 페이지
  • 포스팅마다 category를 지정한 경우, 어떤 category들이 있는지 보여주는 페이지

등이 있고 Single 타입의 페이지는

  • 우리가 작성한 markdown 파일들
  • about 페이지 (자기소개 페이지)

등이 있다.

템플릿 문법

위에서 작성한 list.html파일과 single.html 파일의 내용을 보면 일반적인 html과 다른, {{ }}로 둘러쌓인 형식을 볼 수 있는데 이는 Go 언어에서 지원하는 템플릿 엔진에서 사용하는 문법이다. 미리 작성한 html 문서(템플릿)에서 필요한 부분만 변경하기 위해 템플릿 엔진을 사용한다. 아래 그림을 보면 좀 더 이해가 쉽다.

markdown-to-html

위 그림에 표현되어 있듯 우리가 작성한 markdown 문서가 템플릿을 거쳐 HTML 문서로 생성된다. 템플릿 엔진은 템플릿 파일로 넘어온 markdown 문서 내용을 참조할 수 있는 방법을 제공한다.(그래야 템플릿에 내용을 표현하니까) Hugo의 템플릿에서 참조할 수 있는 변수 종류는 공식문서에 자세히 나와 있다. 여기서는 주로 사용하는 변수만 먼저 살펴보겠다.

  • markdown 문서의 meta data(front matter) 참조
    • title : {{ .Title }}
    • date : {{ .Date }}
    • draft : {{ .Draft }}
  • 우리가 작성한 포스팅 내용
    • {{ .Content }}
  • 그 외 Hugo가 자동으로 생성하는 변수들 (Hugo 공식 문서)

템플릿 문법은 단순히 변수를 참조하는 것 외에 Logic을 표현할 수도 있다. list.html에서 사용했던 아래 문법을 보자.

  • 반복문

    {{ range .Pages }}
        {{ .Title }}
    {{ end }}
    
    • Pages 라는 리스트의 개별 object를 하나씩 참조한다.
    • PagesPage 라는 object를 1개 이상 가진, 리스트 형태다.
    • Page object는 여러가지 속성을 갖고 있는데 대표적으로 Title, URL, Content, Date 등이 있다.
      • 위 single 템플릿에서 참조했던 변수가 바로 Page object.
    • 각 속성은 Page.Title 과 같이 .을 이용하여 접근할 수 있다.
  • 현재 변수 {{ . }}

    • 현재 context를 의미한다.

    • 예를 들어 위 반복문의 경우 {{ range .Pages }} 라고 했을 때 Pages가 갖고 있는 개별 Page object를 참고해야 하는데 이를 . 로 참조 가능하다.

    • Python의 반복문 표현식을 예로 들어 설명하면 아래와 같은 문법을

      for page in pages:
          print(page.title)
      
      • 다음과 같이 축약해서 사용한다고 이해하면 된다. page라는 변수가 반복문 안에서만 쓰이므로 굳이 변수를 선언하지 않고 default 변수로써 . 을 사용하는 방식이다.

        # 아래 문법은 틀린 문법이다. 개념만 보자.
        for pages:
            print(.title)
        

      혹시 Perl 언어를 사용해 본 적이 있다면 $_ 변수와 같은 개념이라고 이해하면 된다.

마치며

Hugo에서 템플릿을 어떤식으로 활용하는지 아주 기본적인 내용을 살펴보았다. 다음 글에서는 템플릿을 좀 더 구조적으로 작성하는 방법에 대해 알아볼 예정이다.