-
-
Notifications
You must be signed in to change notification settings - Fork 97
/
static.go
77 lines (64 loc) · 1.86 KB
/
static.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
package middleware
import (
"io/fs"
"mime"
"net/http"
"os"
"path"
"path/filepath"
"strings"
)
var (
dist = ls("dist")
public = ls("public")
)
func init() {
if err := mime.AddExtensionType(".map", "application/json"); err != nil {
panic(err)
}
}
func ls(dir string) map[string]bool {
files := map[string]bool{}
if err := filepath.WalkDir(dir, func(file string, info fs.DirEntry, err error) error {
if info != nil && !info.IsDir() {
files[file] = true
}
return err
}); err != nil && !os.IsNotExist(err) {
panic(err)
}
return files
}
// Static serves static files from either dist or public.
func Static(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Serves any requested file from dist/. These are immutable & cached.
// Served with the dist prefix, e.g. GET /dist/js/foo-HASH.js.
if file := r.URL.Path[1:]; dist[file] {
w.Header().Set("Cache-Control", "max-age=31536000, public, immutable")
w.Header().Set("Vary", "Accept-Encoding")
// Identify with original filename, not pre-compressed filename.
if ctype := mime.TypeByExtension(filepath.Ext(file)); ctype != "" {
w.Header().Set("Content-Type", ctype)
}
// TODO Content negotiation github.com/golang/go/issues/19307.
accept := r.Header.Get("Accept-Encoding")
if strings.Contains(accept, "br") && dist[file+".br"] {
w.Header().Set("Content-Encoding", "br")
file += ".br"
} else if strings.Contains(accept, "gzip") && dist[file+".gz"] {
w.Header().Set("Content-Encoding", "gzip")
file += ".gz"
}
http.ServeFile(w, r, file)
return
}
// Serves any requested file from public/. These aren't cached.
// Served without a prefix, e.g. GET /robots.txt.
if file := path.Join("public", r.URL.Path); public[file] {
http.ServeFile(w, r, file)
return
}
next.ServeHTTP(w, r)
})
}