Go(golang) html를 재사용하기-1
위 글에 나오는 코드는 이전 글에서 참고한 것입니다. 링크를 참고해 주세요.
먼저 'base.page.tmpl'를 생성해 줍니다.
$ touch ./templates/base.page.tmpl
<!-- base template 시작지점 -->
{{ define "base"}}
<!-- ./templates/base.layout.tmpl -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.0/dist/css/bootstrap.min.css"
integrity="sha384-B0vP5xmATw1+K9KRQjQERJvTumQW0nPEzvF6L/Z6nronJ3oUOFUFpCjEUQouq2+l"
crossorigin="anonymous"
/>
</head>
{{block "css" .}}
{{
end
}}
<body>
{{block "content" .}}
{{ end }}
{{block "js" .}}
{{ end }}
</body>
</html>
<!-- base template 끝나는 지점 -->
{{ end }}
<!-- base template 사용 -->
{{ template "base" .}}
<!-- base template 에서 content에 넣을 내용 정의 -->
{{ define "content" }}
<!-- ./templates/home.page.tmpl -->
<div class="container">
<div class="row">
<div class="col">
<h1>This is the home page</h1>
<p>This is some text</p>
</div>
</div>
</div>
{{ end }}
<!-- base template 사용 -->
{{ template "base"}}
<!-- base template 에서 content에 넣을 내용 정의 -->
{{ define "content" }}
<!-- ./templates/about.page.tmpl -->
<div class="container">
<div class="row">
<div class="col">
<h1>This is the about page</h1>
</div>
</div>
</div>
{{ end }}
위 코드와 같이 home, about, base tmpl을 작성해 줍니다.
하지만 이상태에서는 서버를 구동할수 있지만 실제 home, about페이지는 나오지가 않습니다.
이를 나오게 하기 위해서는 기존 render에서 단순히 templates경로를 이용하여 파싱하는 방법보다 다른 방법을 사용해야 합니다.
// ./render/render.go
package render
import (
"bytes"
"fmt"
"html/template"
"log"
"net/http"
"path/filepath"
)
// 해당 tmpl을 rendering합니다.(해당 함수는 다른 파일에서도 실행되야 하기때문에 첫 알파벳을 대문자로 합니다.)
func RenderTemplate(w http.ResponseWriter, tmpl string) {
// Template Cache를 받기
tc, err := CreateTemplateCache()
if err != nil {
fmt.Println("error parsing template", err)
// 에러시 프로그램 강제로 멈추기
log.Fatal(err)
}
// 요청받은 tmpl의 tmpl페이지 받기
t, ok := tc[tmpl]
if !ok {
fmt.Println("error parsing template", err)
// 에러시 프로그램 강제로 멈추기
log.Fatal(err)
}
// 버퍼속성을 만들어 줍니다.
buf := new(bytes.Buffer)
// 해당 버퍼(buf)에 template를 저장합니다.
_ = t.Execute(buf, nil)
// 버퍼를 이용하여 응답을 보냅니다.
_, err = buf.WriteTo(w)
// 에러 발생시 if문 실행
if err != nil {
fmt.Println("error parsing template", err)
return
}
}
var functions = template.FuncMap{}
// Template 캐쉬를 생성한다.
func CreateTemplateCache() (map[string]*template.Template,error) {
// map으로 해당 템플릿의 메모리 주소를 저장한다.
myCache := map[string]*template.Template{}
// 해당 파일에 들어가서 .page.tmpl로 되어있는 경로를 모두 갖고오기
// 여기서는 home.page.tmpl, about.page.tmpl
pages, err := filepath.Glob("./templates/*.page.tmpl")
fmt.Println("pages :", pages)
if err != nil {
fmt.Println(err)
return map[string]*template.Template{}, err
}
for _, page := range pages {
// 해당 경로에서 파일 이름을 name변수에 저장
name := filepath.Base(page)
// 해당 name을 바탕으로 tmpl페이지를 파싱 한다.
ts, err := template.New(name).Funcs(functions).ParseFiles(page)
if err != nil {
fmt.Println(err)
return map[string]*template.Template{}, err
}
// templates폴더에 있는 파일중 .layout.tmpl이 있는지 확인한다.
matches, err := filepath.Glob("./*templates/*.layout.tmpl")
if err != nil {
fmt.Println(err)
return map[string]*template.Template{}, err
}
// .layout.tmpl이 하나라도 있을시 if문 시행
if len(matches) > 0 {
// 해당 layout을 파싱한다.
ts, err = ts.ParseGlob("./templates/*.layout.tmpl")
if err != nil {
fmt.Println(err)
return map[string]*template.Template{}, err
}
}
myCache[name] = ts
}
return myCache,nil
}
그런데 항상 페이지를 부를때마다 템플릿 캐시를 부르는 것은 비효율 적입니다. 이를 위하여 다음 글에서 동일한 캐시를 사용하는 법에 대해서 확인해 보겠습니다.
댓글
댓글 쓰기