Quicktemplate for Go: Python용 Jinja2처럼, 그러나 html/template은 절대 아님
Lukas Schneider
DevOps Engineer · Leapcell

Quicktemplate 템플릿 라이브러리 사용 가이드
최근 프로젝트 코드를 정리하면서 많은 활동에 대한 코드가 구조와 제공하는 기능 면에서 매우 유사하다는 것을 발견했습니다. 향후 개발을 용이하게 하기 위해 반복적인 작업을 최소화하는 코드 프레임워크 생성 도구를 작성하는 데 시간을 할애했습니다. 코드 자체는 복잡하지 않고 프로젝트 코드와 밀접한 관련이 있으므로 여기서는 자세히 다루지 않습니다. 이 과정에서 Go 표준 템플릿 라이브러리인 text/template
과 html/template
이 다소 제한적이고 사용하기 불편하다는 것을 알게 되었습니다. GitHub에서 강력하고 구문이 간단하며 사용하기 쉬운 타사 템플릿 라이브러리인 quicktemplate
에 대해 알게 되었습니다. 오늘은 quicktemplate
을 소개하겠습니다.
Quick Start
이 문서의 코드는 Go Modules를 사용합니다.
프로젝트 초기화
먼저 코드 디렉토리를 만들고 초기화합니다.
$ mkdir quicktemplate && cd quicktemplate $ go mod init github.com/leapcell/quicktemplate
종속성 설치
quicktemplate
은 우리가 작성한 템플릿 코드를 Go 언어 코드로 변환합니다. 따라서 quicktemplate
패키지와 qtc
라는 컴파일러를 설치해야 합니다.
$ go get -u github.com/valyala/quicktemplate $ go get -u github.com/valyala/quicktemplate/qtc
템플릿 파일 작성
먼저 quicktemplate
형식으로 템플릿 파일을 작성해야 합니다. 템플릿 파일은 기본적으로 .qtpl
확장자를 가집니다. 여기서는 간단한 템플릿 파일 greeting.qtpl
을 작성했습니다.
All text outside function is treated as comments. {% func Greeting(name string, count int) %} {% for i := 0; i < count; i++ %} Hello, {%s name %} {% endfor %} {% endfunc %}
템플릿 구문 설명
템플릿 구문은 매우 간단합니다. 다음 두 가지 사항만 간단히 이해하면 됩니다.
- 템플릿은 함수 단위로 구성됩니다. 함수는 모든 유형과 수량의 매개변수를 허용할 수 있으며, 이러한 매개변수는 함수 내에서 사용할 수 있습니다. 함수 외부의 모든 텍스트는 주석이며,
qtc
컴파일러는 주석을 무시합니다. - 함수의 내용 중 구문 구조를 제외하고는 공백과 줄 바꿈을 포함하여 렌더링된 텍스트에 그대로 출력됩니다.
템플릿 생성 및 사용
greeting.qtpl
을 templates
디렉토리에 저장한 다음 qtc
명령을 실행합니다. 이 명령은 해당 Go 파일 greeting.qtpl.go
를 패키지 이름 templates
로 생성합니다. 이제 이 템플릿을 사용할 수 있습니다.
package main import ( "fmt" "github.com/leapcell/quicktemplate/get-started/templates" ) func main() { fmt.Println(templates.Greeting("leapcell", 5)) }
코드 실행
템플릿 함수를 호출하고 매개변수를 전달하면 렌더링된 텍스트가 반환됩니다.
$ go run .
출력 결과:
Hello, leapcell Hello, leapcell Hello, leapcell Hello, leapcell Hello, leapcell
{%s name %}
은 텍스트를 대체하고, {% for %}
는 반복문을 통해 텍스트를 반복적으로 생성합니다. 출력에 여러 개의 공백과 줄 바꿈이 나타나는 이유는 함수 내의 구문 구조를 제외하고는 다른 내용이 공백과 줄 바꿈을 포함하여 그대로 유지되기 때문입니다.
참고
quicktemplate
은 템플릿을 Go 코드로 변환하여 사용하므로 템플릿이 수정되면 먼저 qtc
명령을 실행하여 Go 코드를 다시 생성해야 합니다. 그렇지 않으면 수정 사항이 적용되지 않습니다.
구문 구조
quicktemplate
은 if
, for
, func
, import
, return
과 같은 일반적인 Go 구문 구조를 지원합니다. 그리고 작성 방식은 Go 코드를 직접 작성하는 것과 크게 다르지 않아 학습 비용이 거의 들지 않습니다. 그러나 템플릿에서 이러한 구문을 사용할 때는 {%
와 %}
로 묶어야 하며, if
, for
등은 endif
, endfor
를 추가하여 끝을 명확하게 나타내야 합니다.
변수
위에서 {%s name %}
을 사용하여 전달된 매개변수 name
을 렌더링하는 방법을 이미 살펴보았습니다. name
이 string
유형이므로 {%
뒤에 s
를 사용하여 유형을 지정합니다. quicktemplate
은 다른 유형의 값도 지원합니다.
- 정수:
{%d int %}
,{%dl int64 %}
,{%dul uint64 %}
. - 부동 소수점 숫자:
{%f float %}
.{%f.precision float %}
을 사용하여 출력 정밀도를 설정할 수도 있습니다. 예를 들어{%f.2 1.2345 %}
은1.23
을 출력합니다. - 바이트 슬라이스 (
[]byte
):{%z bytes %}
. - 문자열:
{%q str %}
또는 바이트 슬라이스:{%qz bytes %}
. 따옴표는"
로 이스케이프됩니다. - 문자열:
{%j str %}
또는 바이트 슬라이스:{%jz bytes %}
. 따옴표가 없습니다. - URL 인코딩:
{%u str %}
,{%uz bytes %}
. {%v anything %}
: 출력은fmt.Sprintf("%v", anything)
과 동일합니다.
샘플 코드
먼저 템플릿을 작성합니다.
{% func Types(a int, b float64, c []byte, d string) %} int: {%d a %}, float64: {%f.2 b %}, bytes: {%z c %}, string with quotes: {%q d %}, string without quotes: {%j d %}. {% endfunc %}
그런 다음 사용합니다.
func main() { fmt.Println(templates.Types(1, 5.75, []byte{'a', 'b', 'c'}, "hello")) }
실행합니다.
$ go run .
출력 결과:
int: 1, float64: 5.75, bytes: abc, string with quotes: "hello", string without quotes: hello.
함수 호출
quicktemplate
은 템플릿 내에서 템플릿 함수와 표준 라이브러리의 함수를 호출하는 것을 지원합니다. qtc
는 Go 코드를 직접 생성하므로 템플릿이 호출할 수 있도록 동일한 디렉터리에 사용자 정의 함수를 작성할 수도 있습니다. 템플릿 A에 정의된 함수는 템플릿 B에 정의된 함수를 호출할 수도 있습니다.
사용자 정의 함수 정의
먼저 templates
디렉터리에 rank.go
파일을 작성하고 점수를 입력받아 등급을 반환하는 Rank
함수를 정의합니다.
package templates func Rank(score int) string { if score >= 90 { return "A" } else if score >= 80 { return "B" } else if score >= 70 { return "C" } else if score >= 60 { return "D" } else { return "E" } }
템플릿에서 사용자 정의 함수 호출
그런 다음 템플릿에서 이 함수를 호출할 수 있습니다.
{% import "fmt" %} {% func ScoreList(name2score map[string]int) %} {% for name, score := range name2score %} {%s fmt.Sprintf("%s: score-%d rank-%s", name, score, Rank(score)) %} {% endfor %} {% endfunc %}
템플릿 컴파일 및 사용
템플릿을 컴파일합니다.
$ qtc
프로그램을 작성합니다.
func main() { name2score := make(map[string]int) name2score["leapcell"] = 85 name2score["bob"] = 86 name2score["alice"] = 22 fmt.Println(templates.ScoreList(name2score)) }
프로그램을 실행하고 출력합니다.
$ go run .
출력 결과:
leapcell: score-85 rank-B bob: score-86 rank-A alice: score-22 rank-E
템플릿에서 fmt
패키지를 사용하므로 먼저 {% import %}
를 사용하여 패키지를 가져와야 합니다. 템플릿이 결국 Go 코드로 변환되고 Go 코드에 동일한 서명을 가진 함수가 있기 때문에 템플릿에서 다른 템플릿의 함수를 호출하는 것도 유사합니다.
웹 애플리케이션
quicktemplate
은 종종 HTML 페이지용 템플릿을 작성하는 데 사용됩니다.
{% func Index(name string) %} <html> <head> <title>Awesome Web</title> </head> <body> <h1>Hi, {%s name %} <p>Welcome to the awesome web!!!</p> </body> </html> {% endfunc %}
다음으로 간단한 웹 서버를 작성합니다.
func index(w http.ResponseWriter, r *http.Request) { templates.WriteIndex(w, r.FormValue("name")) } func main() { mux := http.NewServeMux() mux.HandleFunc("/", index) server := &http.Server{ Handler: mux, Addr: ":8080", } log.Fatal(server.ListenAndServe()) }
qtc
는 io.Writer
유형의 매개변수를 허용하는 Write*
메서드를 생성합니다. 템플릿 렌더링 결과는 이 io.Writer
에 기록됩니다. http.ResponseWriter
를 매개변수로 직접 전달할 수 있어 매우 편리합니다.
웹 서버 실행
$ qtc $ go run .
브라우저에 localhost:8080?name=leapcell
을 입력하여 결과를 확인합니다.
결론
quicktemplate
은 다음과 같은 세 가지 이상의 장점이 있습니다.
- 구문이 Go 언어와 매우 유사하여 학습 비용이 거의 들지 않습니다.
- 먼저 Go로 변환되어 렌더링 속도가 매우 빠르며 표준 라이브러리
html/template
보다 20배 이상 빠릅니다. - 보안상의 이유로 공격을 피하기 위해 일부 인코딩을 수행합니다.
Leapcell: 최고의 서버리스 웹 호스팅
마지막으로 Go 서비스를 배포하는 데 가장 적합한 플랫폼인 **Leapcell**을 추천합니다.
🚀 좋아하는 언어로 구축
JavaScript, Python, Go 또는 Rust로 손쉽게 개발하세요.
🌍 무제한 프로젝트 무료 배포
사용한 만큼만 지불하세요. 요청도 없고, 요금도 없습니다.
⚡ 사용량에 따라 지불, 숨겨진 비용 없음
유휴 요금 없이 원활하게 확장 가능합니다.
🔹 Twitter에서 팔로우하세요: @LeapcellHQ