Go

Go 언어의 go:embed 완벽 가이드 - 사용법과 주의사항

드리프트2 2024. 10. 6. 21:51

Go 언어의 go:embed 완벽 가이드 - 사용법과 주의사항


서론

안녕하세요!

 

옛날 버전이지만 오늘은 Go 1.16에 새롭게 도입된 go:embed 디렉티브에 대해 깊이 있게 알아보려고 합니다.

 

이번 업데이트는 Go의 빌드된 바이너리에 정적 파일을 손쉽게 포함할 수 있는 기능을 제공하며, 이를 통해 다양한 개발자들이 보다 편리하게 프로젝트를 관리할 수 있게 되었습니다.

 

그럼 go:embed가 무엇인지, 어떻게 사용하는지 함께 살펴볼까요?

 

go:embed란 무엇인가?

go:embed는 Go의 빌드 바이너리에 정적 자원을 포함할 수 있게 해주는 디렉티브입니다.

 

이전에는 정적 파일을 바이너리에 포함시키기 위해 여러 가지 방법과 도구를 사용해야 했지만, 이번에 공식적으로 도입된 go:embed 덕분에 이러한 번거로움이 크게 줄어들었습니다.

 

이 디렉티브를 사용하면 파일을 손쉽게 포함시키고, 코드 내에서 직접 접근할 수 있습니다.

 

go:embed 사용법

go:embed를 사용하기 위해서는 먼저 embed 패키지를 임포트해야 합니다.

 

만약 패키지를 직접 사용하지 않는다면, 블랭크 임포트를 통해 임포트해 줄 수 있습니다.

 

import _ "embed"

 

이제 go:embed 디렉티브를 활용하여 파일을 변수에 임베드할 수 있습니다.

 

임베드할 파일은 현재 디렉토리 또는 그 하위 디렉토리에 위치해야 하며, 상대 경로를 사용하여 지정할 수 있습니다.

 

예제: 단일 파일 임베드

//go:embed hello.txt
var hello string

 

이 예제에서는 hello.txt 파일의 내용을 hello 변수에 문자열로 임베드합니다.

 

만약 같은 파일을 여러 번 임베드하려고 하면 컴파일 에러가 발생합니다.

 

예제: 여러 파일 임베드 및 파일 시스템

//go:embed images/* templates/*
//go:embed styles/*.css
//go:embed html/index.html
var assets embed.FS

 

위의 예제에서는 여러 파일과 디렉토리를 assets 변수에 임베드합니다.

 

embed.FS 타입을 사용하면 임베드된 파일을 계층 구조 파일 시스템처럼 접근할 수 있습니다.

 

와일드카드를 사용하여 특정 패턴에 맞는 파일들을 한 번에 임베드할 수도 있습니다.

 

go:embed의 주요 기능

  • 문자열 임베드: 단일 파일을 문자열 변수에 임베드할 수 있습니다.
  • 바이트 슬라이스 임베드: 파일의 내용을 바이트 슬라이스에 임베드할 수 있습니다.
  • 파일 시스템 임베드: 여러 파일과 디렉토리를 임베드하여 embed.FS로 접근할 수 있습니다.
  • 로컬 및 글로벌 임베드: 글로벌 변수뿐만 아니라 함수 내에서도 파일을 임베드할 수 있습니다.

 

go:embed 사용 시 주의사항

go:embed를 사용할 때 몇 가지 주의해야 할 점이 있습니다.

 

이를 잘 지키지 않으면 의도하지 않은 컴파일 에러가 발생할 수 있습니다.

 

중복 파일 임베드

동일한 파일을 여러 번 임베드하려고 하면 컴파일 에러가 발생합니다.

 

예를 들어, 다음과 같이 같은 파일을 두 번 임베드하려고 하면 문제가 됩니다.

//go:embed foo.txt
//go:embed foo.txt
var foo string

 

이 경우, foo.txt 파일을 두 번 임베드했기 때문에 컴파일 에러가 발생합니다.

 

빈 디렉토리 임베드

go:embed는 파일을 임베드할 때, 비어 있는 디렉토리를 임베드하려고 하면 컴파일 에러가 발생합니다.

 

임베드하려는 디렉토리 안에 최소한 하나 이상의 파일이 있어야 합니다.

//go:embed empty_dir/*
var files embed.FS

 

위의 예제에서 empty_dir이 비어 있다면 컴파일 에러가 발생합니다.

 

잘못된 파일 경로

존재하지 않는 파일을 임베드하려고 하면 당연히 컴파일 에러가 발생합니다.

 

임베드하려는 파일의 경로를 정확히 지정해야 합니다.

//go:embed non_existent.txt
var data string

 

non_existent.txt 파일이 존재하지 않으면 컴파일 에러가 발생합니다.

 

디렉토리 경로 지정 시 주의

디렉토리를 임베드할 때는 반드시 경로 끝에 슬래시(/)를 포함시켜야 합니다.

 

그렇지 않으면 디렉토리 자체가 아닌 파일을 임베드하려는 시도로 간주되어 에러가 발생할 수 있습니다.

// 잘못된 예
//go:embed assets
var assets embed.FS

// 올바른 예
//go:embed assets/*
var assets embed.FS

go:embed를 활용한 실전 예제

 

이제 go:embed를 활용한 간단한 예제를 통해 실제 사용법을 살펴보겠습니다.

 

예제: HTML 템플릿 임베드

package main

import (
    "embed"
    "fmt"
    "io/fs"
    "net/http"
)

//go:embed templates/*
var templates embed.FS

func main() {
    tmplFS, err := fs.Sub(templates, "templates")
    if err != nil {
        panic(err)
    }

    fs := http.FileServer(http.FS(tmplFS))
    http.Handle("/", fs)

    fmt.Println("서버가 시작되었습니다. http://localhost:8080 에 접속해보세요.")
    http.ListenAndServe(":8080", nil)
}

 

위의 예제는 templates 디렉토리에 있는 모든 HTML 파일을 임베드하여 간단한 웹 서버를 구축하는 코드입니다.

 

fs.Sub 함수를 사용하여 임베드된 파일 시스템을 서브 디렉토리로 분리한 후, http.FileServer를 통해 파일을 서빙합니다.

 

결론

go:embed는 Go 언어에서 정적 파일을 쉽게 임베드할 수 있게 해주는 강력한 도구입니다.

 

이를 잘 활용하면 프로젝트의 배포와 관리가 훨씬 수월해지며, 코드 내에서 직접 파일을 다룰 수 있어 편리합니다.

 

다만, 몇 가지 주의사항을 잘 숙지하고 사용해야 의도한 대로 동작할 수 있습니다.

 

이번 글을 통해 go:embed의 기본 사용법과 주의사항을 이해하고, 여러분의 프로젝트에 효과적으로 적용해보시기 바랍니다.