~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.


c6ec8c41 pyros2097

4 years ago
reduce wasm size by 1.3mb (do not use net/http package)
Files changed (4) hide show
  1. app_wasm.go +1 -0
  2. example/makefile +1 -1
  3. router.go +8 -115
  4. router_nowasm.go +116 -0
app_wasm.go CHANGED
@@ -1,4 +1,5 @@
1
1
  // +build wasm
2
+
2
3
  package app
3
4
 
4
5
  import (
example/makefile CHANGED
@@ -4,7 +4,7 @@ run:
4
4
  wasm: export GOOS=js
5
5
  wasm: export GOARCH=wasm
6
6
  wasm:
7
- go build -o assets/main.wasm
7
+ go build -ldflags='-s -w' -o assets/main.wasm
8
8
 
9
9
  css:
10
10
  npx tailwindcss-cli@latest build assets/config.css -o assets/styles.css
router.go CHANGED
@@ -1,15 +1,10 @@
1
1
  package app
2
2
 
3
3
  import (
4
- "bytes"
5
4
  "context"
6
- "net/http"
7
5
  "strings"
8
6
  "unicode"
9
7
  "unicode/utf8"
10
-
11
- "github.com/aws/aws-lambda-go/events"
12
- "github.com/pyros2097/wapp/errors"
13
8
  )
14
9
 
15
10
  func min(a, b int) int {
@@ -761,23 +756,24 @@ var AppRouter = &Router{
761
756
  },
762
757
  }
763
758
 
764
- // GET is a shortcut for router.Handle(http.MethodGet, path, handle)
759
+ // GET route
765
760
  func (r *Router) GET(path string, handle interface{}) {
766
- r.Handle(http.MethodGet, path, handle)
761
+ r.Handle("GET", path, handle)
767
762
  }
768
763
 
764
+ // POST route
769
765
  func (r *Router) POST(path string, handle interface{}) {
770
- r.Handle(http.MethodPost, path, handle)
766
+ r.Handle("POST", path, handle)
771
767
  }
772
768
 
773
- // PUT is a shortcut for router.Handle(http.MethodPut, path, handle)
769
+ // PUT route
774
770
  func (r *Router) PUT(path string, handle interface{}) {
775
- r.Handle(http.MethodPut, path, handle)
771
+ r.Handle("PUT", path, handle)
776
772
  }
777
773
 
778
- // DELETE is a shortcut for router.Handle(http.MethodDelete, path, handle)
774
+ // DELETE route
779
775
  func (r *Router) DELETE(path string, handle interface{}) {
780
- r.Handle(http.MethodDelete, path, handle)
776
+ r.Handle("DELETE", path, handle)
781
777
  }
782
778
 
783
779
  // Handle registers a new request handle with the given path and method.
@@ -842,106 +838,3 @@ func (r *Router) Lookup(method, path string) (interface{}, Params, bool) {
842
838
  }
843
839
  return nil, nil, false
844
840
  }
845
-
846
- // ServeHTTP makes the router implement the http.Handler interface.
847
- func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
848
- // Handle errors
849
- defer func() {
850
- if rcv := recover(); rcv != nil {
851
- var err error
852
- switch x := rcv.(type) {
853
- case string:
854
- err = errors.New(x)
855
- case error:
856
- err = x
857
- default:
858
- err = errors.New("unknown panic")
859
- }
860
- w.Header().Set("Content-Type", "text/html")
861
- w.WriteHeader(http.StatusInternalServerError)
862
- writePage(r.Error(NewRenderContext(), err), w)
863
- }
864
- }()
865
-
866
- path := req.URL.Path
867
- println("route: " + req.URL.Path)
868
-
869
- if root := r.trees[req.Method]; root != nil {
870
- // TODO: use _ ps save it to context for useParam()
871
- if handle, _, tsr := root.getValue(path, nil); handle != nil {
872
- if render, ok := handle.(RenderFunc); ok {
873
- w.Header().Set("Content-Type", "text/html")
874
- w.WriteHeader(http.StatusOK)
875
- writePage(render(NewRenderContext()), w)
876
- return
877
- } else {
878
- handle.(func(w http.ResponseWriter, r *http.Request))(w, req)
879
- return
880
- }
881
-
882
- } else if req.Method != http.MethodConnect && path != "/" {
883
- // Moved Permanently, request with GET method
884
- code := http.StatusMovedPermanently
885
- if req.Method != http.MethodGet {
886
- // Permanent Redirect, request with same method
887
- code = http.StatusPermanentRedirect
888
- }
889
-
890
- if tsr && r.RedirectTrailingSlash {
891
- if len(path) > 1 && path[len(path)-1] == '/' {
892
- req.URL.Path = path[:len(path)-1]
893
- } else {
894
- req.URL.Path = path + "/"
895
- }
896
- http.Redirect(w, req, req.URL.String(), code)
897
- return
898
- }
899
- }
900
- }
901
-
902
- // Handle 404
903
- w.Header().Set("Content-Type", "text/html")
904
- w.WriteHeader(http.StatusNotFound)
905
- writePage(r.NotFound(NewRenderContext()), w)
906
- }
907
-
908
- func (r *Router) getPage(ui UI) string {
909
- b := bytes.NewBuffer(nil)
910
- writePage(ui, b)
911
- return b.String()
912
- }
913
-
914
- func (r *Router) Lambda(ctx context.Context, e events.APIGatewayV2HTTPRequest) (res events.APIGatewayV2HTTPResponse, err error) {
915
- res.StatusCode = 200
916
- res.Headers = map[string]string{
917
- "Content-Type": "text/html",
918
- }
919
- // Handle errors
920
- defer func() {
921
- if rcv := recover(); rcv != nil {
922
- switch x := rcv.(type) {
923
- case string:
924
- err = errors.New(x)
925
- case error:
926
- err = x
927
- default:
928
- err = errors.New("unknown panic")
929
- }
930
- res.Body = r.getPage(r.Error(NewRenderContext(), err))
931
- }
932
- }()
933
-
934
- println("route: " + e.RawPath)
935
- path := strings.Replace(e.RawPath, "/Prod/", "/", 1)
936
- if root := r.trees[e.RequestContext.HTTP.Method]; root != nil {
937
- if handle, _, _ := root.getValue(path, nil); handle != nil {
938
- res.Body = r.getPage(handle.(RenderFunc)(NewRenderContext()))
939
- return
940
- }
941
- }
942
-
943
- // Handle 404
944
- res.StatusCode = http.StatusNotFound
945
- res.Body = r.getPage(r.NotFound(NewRenderContext()))
946
- return
947
- }
router_nowasm.go ADDED
@@ -0,0 +1,116 @@
1
+ // +build !wasm
2
+
3
+ package app
4
+
5
+ import (
6
+ "bytes"
7
+ "context"
8
+ "net/http"
9
+ "strings"
10
+
11
+ "github.com/aws/aws-lambda-go/events"
12
+ "github.com/pyros2097/wapp/errors"
13
+ )
14
+
15
+ // ServeHTTP makes the router implement the http.Handler interface.
16
+ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
17
+ // Handle errors
18
+ defer func() {
19
+ if rcv := recover(); rcv != nil {
20
+ var err error
21
+ switch x := rcv.(type) {
22
+ case string:
23
+ err = errors.New(x)
24
+ case error:
25
+ err = x
26
+ default:
27
+ err = errors.New("unknown panic")
28
+ }
29
+ w.Header().Set("Content-Type", "text/html")
30
+ w.WriteHeader(http.StatusInternalServerError)
31
+ writePage(r.Error(NewRenderContext(), err), w)
32
+ }
33
+ }()
34
+
35
+ path := req.URL.Path
36
+ println("route: " + req.URL.Path)
37
+
38
+ if root := r.trees[req.Method]; root != nil {
39
+ // TODO: use _ ps save it to context for useParam()
40
+ if handle, _, tsr := root.getValue(path, nil); handle != nil {
41
+ if render, ok := handle.(RenderFunc); ok {
42
+ w.Header().Set("Content-Type", "text/html")
43
+ w.WriteHeader(http.StatusOK)
44
+ writePage(render(NewRenderContext()), w)
45
+ return
46
+ } else {
47
+ handle.(func(w http.ResponseWriter, r *http.Request))(w, req)
48
+ return
49
+ }
50
+
51
+ } else if req.Method != http.MethodConnect && path != "/" {
52
+ // Moved Permanently, request with GET method
53
+ code := http.StatusMovedPermanently
54
+ if req.Method != http.MethodGet {
55
+ // Permanent Redirect, request with same method
56
+ code = http.StatusPermanentRedirect
57
+ }
58
+
59
+ if tsr && r.RedirectTrailingSlash {
60
+ if len(path) > 1 && path[len(path)-1] == '/' {
61
+ req.URL.Path = path[:len(path)-1]
62
+ } else {
63
+ req.URL.Path = path + "/"
64
+ }
65
+ http.Redirect(w, req, req.URL.String(), code)
66
+ return
67
+ }
68
+ }
69
+ }
70
+
71
+ // Handle 404
72
+ w.Header().Set("Content-Type", "text/html")
73
+ w.WriteHeader(http.StatusNotFound)
74
+ writePage(r.NotFound(NewRenderContext()), w)
75
+ }
76
+
77
+ func (r *Router) getPage(ui UI) string {
78
+ b := bytes.NewBuffer(nil)
79
+ writePage(ui, b)
80
+ return b.String()
81
+ }
82
+
83
+ func (r *Router) Lambda(ctx context.Context, e events.APIGatewayV2HTTPRequest) (res events.APIGatewayV2HTTPResponse, err error) {
84
+ res.StatusCode = 200
85
+ res.Headers = map[string]string{
86
+ "Content-Type": "text/html",
87
+ }
88
+ // Handle errors
89
+ defer func() {
90
+ if rcv := recover(); rcv != nil {
91
+ switch x := rcv.(type) {
92
+ case string:
93
+ err = errors.New(x)
94
+ case error:
95
+ err = x
96
+ default:
97
+ err = errors.New("unknown panic")
98
+ }
99
+ res.Body = r.getPage(r.Error(NewRenderContext(), err))
100
+ }
101
+ }()
102
+
103
+ println("route: " + e.RawPath)
104
+ path := strings.Replace(e.RawPath, "/Prod/", "/", 1)
105
+ if root := r.trees[e.RequestContext.HTTP.Method]; root != nil {
106
+ if handle, _, _ := root.getValue(path, nil); handle != nil {
107
+ res.Body = r.getPage(handle.(RenderFunc)(NewRenderContext()))
108
+ return
109
+ }
110
+ }
111
+
112
+ // Handle 404
113
+ res.StatusCode = http.StatusNotFound
114
+ res.Body = r.getPage(r.NotFound(NewRenderContext()))
115
+ return
116
+ }