Golang встраиваем статику в двоичный файл (с примером сборки React)
Известно, что Go создает статически связанные двоичные файлы без каких-либо зависимостей во время выполнения. Статические двоичные файлы отлично подходят для развертывания, поскольку для них нужен только один файл, что снижает вероятность возникновения проблем, связанных с envionment.
Но есть одна проблема: если вы хотите встроить некоторые статические ресурсы (интерфейсные файлы, изображения и т. д.), то у вас не было собственного способа сделать это.
Это меняется в Go 1.16, Go представляет новый пакет embed
для решения этой проблемы.
Как использовать embed
Есть 3 способа использования встроенного пакета.
- Получить файл как строку
- Получить файл как байтовый фрагмент
- Получить файл(ы) как тип
embed.FS
Даже если embed
на пакет не ссылаются первыми 2 способами, он должен быть импортирован. Его можно импортировать как import _ "embed"
Получить файл как строку
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var s string
func main() {
fmt.Println(s)
}
Получить файл как [] байт
package main
import (
_ "embed"
"fmt"
)
//go:embed hello.txt
var b []byte
func main() {
fmt.Println(string(b))
}
Получить файл как embed.FS
package main
import (
"embed"
"fmt"
)
//go:embed hello.txt
var f embed.FS
func main() {
data, _ := f.ReadFile("hello.txt")
print(string(data))
}
Как обслуживать клиентское приложение с помощью Go Embed
Давайте посмотрим, как мы можем обслуживать любой каталог сборки внешнего интерфейса, используя embed
.
Измените имя файла на путь к файлу в комментарии go:embed
. Как показано ниже
//go:embed client/build
var content embed.FS // build directory holds a client react build
Go 1.16 также внес еще несколько изменений, таких как http.FS
и еще один пакет io/fs
, чтобы облегчить работу с файловой системой.
Чтобы преобразовать embed.FS
в http.FileSystem
, можно использовать:
http.Handle("/", http.FileServer(http.FS(content)))
Но есть одна проблема, в index.html
теперь нам нужно получить доступ к файлам HOST/client/build
. Нам нужно обслуживать подкаталог контента, который мы можем получить с помощью
fsys := fs.FS(content)
contentStatic, _ := fs.Sub(fsys, "client/build")
Окончательный код
package main
import (
"embed"
"io/fs"
"net/http"
)
//go:embed client/build
var content embed.FS
func clientHandler() http.Handler {
fsys := fs.FS(content)
contentStatic, _ := fs.Sub(fsys, "client/build")
return http.FileServer(http.FS(contentStatic))
}
func main() {
mux := http.NewServeMux()
mux.Handle("/", clientHandler())
http.ListenAndServe(":3000", mux)
}