Go 1.15에서 embed 패턴으로 정적 파일 관리하기
배경
회사에서 관리하던 내부 도구를 Node.js에서 Go로 마이그레이션했다. 단일 바이너리 배포가 목적이었는데, HTML 템플릿과 CSS 파일을 함께 번들링하는 방법이 필요했다.
go-bindata 사용
가장 많이 쓰이는 방법은 go-bindata였다.
go get -u github.com/go-bindata/go-bindata/...
go-bindata -o assets.go -pkg main static/...
생성된 assets.go에서 파일을 읽는다:
data, err := Asset("static/index.html")
if err != nil {
log.Fatal(err)
}
문제는 빌드 과정이 복잡해진다는 점이다. CI/CD 파이프라인에 go-bindata 설치와 생성 스크립트를 추가해야 했다.
직접 구현
작은 프로젝트라 직접 구현도 고려했다.
var templates = map[string]string{
"index": `<!DOCTYPE html>
<html>
<head><title>Tool</title></head>
<body>...</body>
</html>`,
}
func getTemplate(name string) string {
return templates[name]
}
파일이 적을 때는 이게 더 명확했다. 하지만 템플릿이 늘어나면서 유지보수가 어려워졌다.
선택
결국 go-bindata를 선택했다. Makefile에 생성 과정을 추가하고, 생성된 파일은 .gitignore에 등록했다.
generate:
go-bindata -o internal/assets/assets.go -pkg assets static/...
build: generate
go build -o bin/tool cmd/main.go
Go 1.16에서 //go:embed 디렉티브가 추가된다는 소식을 들었다. 그때 가면 다시 마이그레이션할 예정이다.
참고
- 개발 환경에서는
-debug플래그로 실제 파일을 읽도록 해서 핫 리로드 구현 - 프로덕션 빌드만 임베드된 파일 사용