~repos /gromer

#golang#htmx#ssr

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.


937a71ad Peter John

tag: v0.18.0

v0.18.0

3 years ago
add caching layer
Files changed (2) hide show
  1. _example/components/page.go +12 -5
  2. 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="/assets/css/bulma@0.9.3.css" />
30
+ <link rel="stylesheet" href="{{ bulmaCssUrl }}" />
29
- <link rel="stylesheet" href="/styles.css" />
31
+ <link rel="stylesheet" href="{{ stylesCssUrl }}" />
30
- <script src="/assets/js/htmx@1.7.0.js"></script>
32
+ <script src="{{ htmxJsUrl }}"></script>
31
- <script src="/assets/js/alpinejs@3.9.6.js" defer=""></script>
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
+ }