Skip to content

Instantly share code, notes, and snippets.

@FrancescoLuzzi
Last active December 4, 2024 05:14
Show Gist options
  • Save FrancescoLuzzi/7ad74721faa8af56e2d03ef452448380 to your computer and use it in GitHub Desktop.
Save FrancescoLuzzi/7ad74721faa8af56e2d03ef452448380 to your computer and use it in GitHub Desktop.
Serve precompressed files in fiber golang
package public
import (
"fmt"
"mime"
"path"
"sync"
"github.com/gofiber/fiber/v3"
"github.com/gofiber/fiber/v3/middleware/static"
)
func Asset(name string) string {
return fmt.Sprintf("/public/assets/%s", name)
}
var (
compressExtensions map[string]string
onceExtensions sync.Once
)
func init() {
mime.AddExtensionType(".js", "text/javascript; charset=utf-8")
mime.AddExtensionType(".css", "text/css; charset=utf-8")
mime.AddExtensionType(".json", "text/json; charset=utf-8")
}
func getCompressExtensions(ctx fiber.Ctx) map[string]string {
onceExtensions.Do(func() {
compressExtensions = ctx.App().Config().CompressedFileSuffixes
})
return compressExtensions
}
func searchExtensionEncoding(ext string, encodings map[string]string) string {
for encName, encExt := range encodings {
if encExt == ext {
return encName
}
}
return ""
}
const (
contentEncodingHeader = "Content-Encoding"
contentTypeHeader = "Content-Type"
cacheControlHeader = "Cache-Control"
)
// when creating the fiber application I suggest to configure it like so:
// app := fiber.New(fiber.Config{
// CompressedFileSuffixes: map[string]string{
// "gzip": ".gz",
// "br": ".br",
// "zstd": ".zst",
// },
// })
func RegisterAssets(app *fiber.App) {
app.Use("/public/assets/*", static.New("", static.Config{
FS: AssetFs(),
Compress: true,
ModifyResponse: func(c fiber.Ctx) error {
urlPath := c.Request().URI().String()
ext := path.Ext(urlPath)
// get last extension ES: .js.gz -> .gz
enc := searchExtensionEncoding(ext, getCompressExtensions(c))
if enc != "" {
c.Set(contentEncodingHeader, enc)
enc = ""
// get compressed file extension ES: .js.gz -> .js
ext = path.Ext(urlPath[:len(urlPath)-len(ext)])
enc = mime.TypeByExtension(ext)
if enc != "" {
c.Set(contentTypeHeader, enc)
}
}
return nil
},
}))
}
//go:build !prod
// +build !prod
package public
import (
"io/fs"
"os"
"sync"
)
var (
onceFS sync.Once
assetsFS fs.FS
)
func AssetFs() fs.FS {
onceFS.Do(func() {
assetsFS = os.DirFS("public/assets")
})
return assetsFS
}
//go:build prod
// +build prod
package public
import (
"embed"
"io/fs"
"sync"
)
//go:embed assets
var staticAssetsFS embed.FS
var (
onceFS sync.Once
assetsFS fs.FS
)
func AssetFs() fs.FS {
onceFS.Do(func() {
assetsFS, _ = fs.Sub(staticAssetsFS, "assets")
})
return assetsFS
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment