~repos /gromer
git clone https://pyrossh.dev/repos/gromer.git
gromer is a framework and cli to build multipage web apps in golang using htmx and alpinejs.
add caching layer
- _example/components/page.go +12 -5
- http.go +32 -1
_example/components/page.go
CHANGED
|
@@ -3,6 +3,8 @@ package components
|
|
|
3
3
|
import (
|
|
4
4
|
"html/template"
|
|
5
5
|
|
|
6
|
+
"github.com/pyros2097/gromer"
|
|
7
|
+
"github.com/pyros2097/gromer/_example/assets"
|
|
6
8
|
. "github.com/pyros2097/gromer/handlebars"
|
|
7
9
|
)
|
|
8
10
|
|
|
@@ -25,14 +27,19 @@ func Page(props PageProps) *Template {
|
|
|
25
27
|
<meta content="pyros.sh, gromer" name="keywords" />
|
|
26
28
|
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0, viewport-fit=cover" />
|
|
27
29
|
<link rel="icon" href="/assets/icon.png" />
|
|
28
|
-
<link rel="stylesheet" href="
|
|
30
|
+
<link rel="stylesheet" href="{{ bulmaCssUrl }}" />
|
|
29
|
-
<link rel="stylesheet" href="
|
|
31
|
+
<link rel="stylesheet" href="{{ stylesCssUrl }}" />
|
|
30
|
-
<script src="
|
|
32
|
+
<script src="{{ htmxJsUrl }}"></script>
|
|
31
|
-
<script src="
|
|
33
|
+
<script src="{{ alpineJsUrl }}" defer=""></script>
|
|
32
34
|
</head>
|
|
33
35
|
<body>
|
|
34
36
|
{{ props.Children }}
|
|
35
37
|
</body>
|
|
36
38
|
</html>
|
|
39
|
+
`).Props(
|
|
40
|
+
"bulmaCssUrl", gromer.GetAssetUrl(assets.FS, "css/bulma@0.9.3.css"),
|
|
41
|
+
"stylesCssUrl", gromer.GetStylesUrl(),
|
|
42
|
+
"htmxJsUrl", gromer.GetAssetUrl(assets.FS, "js/htmx@1.7.0.js"),
|
|
43
|
+
"alpineJsUrl", gromer.GetAssetUrl(assets.FS, "js/alpinejs@3.9.6.js"),
|
|
37
|
-
|
|
44
|
+
)
|
|
38
45
|
}
|
http.go
CHANGED
|
@@ -2,6 +2,7 @@ package gromer
|
|
|
2
2
|
|
|
3
3
|
import (
|
|
4
4
|
"context"
|
|
5
|
+
"crypto/md5"
|
|
5
6
|
"embed"
|
|
6
7
|
"encoding/json"
|
|
7
8
|
"fmt"
|
|
@@ -16,6 +17,7 @@ import (
|
|
|
16
17
|
"runtime/debug"
|
|
17
18
|
"strconv"
|
|
18
19
|
"strings"
|
|
20
|
+
"sync"
|
|
19
21
|
"time"
|
|
20
22
|
|
|
21
23
|
"github.com/go-playground/validator/v10"
|
|
@@ -372,7 +374,7 @@ func StatusHandler(h interface{}) http.Handler {
|
|
|
372
374
|
|
|
373
375
|
func WrapCache(h http.Handler) http.Handler {
|
|
374
376
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
375
|
-
w.Header().Set("Cache-Control", "public, max-age=2592000")
|
|
377
|
+
w.Header().Set("Cache-Control", "public, max-age=2592000") // perma cache for 1 month
|
|
376
378
|
h.ServeHTTP(w, r)
|
|
377
379
|
})
|
|
378
380
|
}
|
|
@@ -400,3 +402,32 @@ func GetUrl(ctx context.Context) *url.URL {
|
|
|
400
402
|
func GetHeader(ctx context.Context) http.Header {
|
|
401
403
|
return ctx.Value("header").(http.Header)
|
|
402
404
|
}
|
|
405
|
+
|
|
406
|
+
var sumCache = sync.Map{}
|
|
407
|
+
|
|
408
|
+
func getSum(k string, cb func() [16]byte) string {
|
|
409
|
+
if v, ok := sumCache.Load(k); ok {
|
|
410
|
+
return v.(string)
|
|
411
|
+
}
|
|
412
|
+
sum := fmt.Sprintf("%x", cb())
|
|
413
|
+
sumCache.Store(k, sum)
|
|
414
|
+
return sum
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
func GetAssetUrl(fs embed.FS, path string) string {
|
|
418
|
+
sum := getSum(path, func() [16]byte {
|
|
419
|
+
data, err := fs.ReadFile(path)
|
|
420
|
+
if err != nil {
|
|
421
|
+
panic(err)
|
|
422
|
+
}
|
|
423
|
+
return md5.Sum(data)
|
|
424
|
+
})
|
|
425
|
+
return fmt.Sprintf("/assets/%s?hash=%s", path, sum)
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
func GetStylesUrl() string {
|
|
429
|
+
sum := getSum("styles.css", func() [16]byte {
|
|
430
|
+
return md5.Sum([]byte(handlebars.GetStyles()))
|
|
431
|
+
})
|
|
432
|
+
return fmt.Sprintf("/styles.css?hash=%s", sum)
|
|
433
|
+
}
|