├── README.md
├── go.mod
├── main.go
└── go.sum
/README.md:
--------------------------------------------------------------------------------
1 | # Datastar minimal repro for morph vs replace
2 |
3 | This is a minimal reproduction to demonstrate the difference between using `morph` and `replace` and how it affects the evaluation of data-attr-\* attributes in updated elements.
4 |
5 | # Part 2: `data-on-datastar-sse` broken in RC.2
6 |
--------------------------------------------------------------------------------
/go.mod:
--------------------------------------------------------------------------------
1 | module datastar-repro
2 |
3 | go 1.24.4
4 |
5 | require github.com/starfederation/datastar-go v1.0.1
6 |
7 | require (
8 | github.com/CAFxX/httpcompression v0.0.9 // indirect
9 | github.com/andybalholm/brotli v1.1.1 // indirect
10 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
11 | github.com/klauspost/compress v1.18.0 // indirect
12 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
13 | github.com/stretchr/testify v1.10.0 // indirect
14 | github.com/valyala/bytebufferpool v1.0.0 // indirect
15 | )
16 |
17 | replace github.com/starfederation/datastar => github.com/starfederation/datastar v1.0.0-RC.1
18 |
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "bytes"
5 | "html/template"
6 | "net/http"
7 | "os"
8 |
9 | "github.com/starfederation/datastar-go/datastar"
10 | )
11 |
12 | var customers = []struct {
13 | ID string
14 | Name string
15 | }{
16 | {"1", "Alice"},
17 | {"2", "Bob"},
18 | {"3", "Charlie"},
19 | }
20 |
21 | var currentID = "1"
22 |
23 | func main() {
24 | http.HandleFunc("/", handleIndex)
25 |
26 | // default morph - doesn't work
27 | http.HandleFunc("/sse/nav", handleNavSSE)
28 |
29 | // replace approach - works
30 | http.HandleFunc("/sse/nav-replace", handleNavReplaceSSE)
31 |
32 | port := os.Getenv("PORT")
33 | if port == "" {
34 | port = "8080"
35 | }
36 | println("Listening on :" + port)
37 | http.ListenAndServe(":"+port, nil)
38 | }
39 |
40 | func handleIndex(w http.ResponseWriter, r *http.Request) {
41 | tmpl := template.Must(template.New("index").Parse(indexHTML))
42 | id := currentID
43 |
44 | tmpl.Execute(w, struct {
45 | Customers []struct{ ID, Name string }
46 | CurrentID string
47 | }{customers, id})
48 | }
49 |
50 | func handleNavSSE(w http.ResponseWriter, r *http.Request) {
51 | id := r.URL.Query().Get("id")
52 | if id == "" {
53 | id = "1"
54 | }
55 | currentID = id
56 |
57 | buf := &bytes.Buffer{}
58 | tmpl := template.Must(template.New("nav").Parse(navHTML))
59 |
60 | tmpl.Execute(buf, struct {
61 | Customers []struct{ ID, Name string }
62 | CurrentID string
63 | }{customers, id})
64 |
65 | sse := datastar.NewSSE(w, r)
66 | sse.PatchSignals([]byte(`{"currentID":"` + id + `"}`))
67 | sse.PatchElements(buf.String())
68 | }
69 |
70 | func handleNavReplaceSSE(w http.ResponseWriter, r *http.Request) {
71 | id := r.URL.Query().Get("id")
72 | if id == "" {
73 | id = "1"
74 | }
75 |
76 | currentID = id
77 | buf := &bytes.Buffer{}
78 | tmpl := template.Must(template.New("nav").Parse(navHTML))
79 |
80 | tmpl.Execute(buf, struct {
81 | Customers []struct{ ID, Name string }
82 | CurrentID string
83 | }{customers, id})
84 |
85 | sse := datastar.NewSSE(w, r)
86 | sse.PatchSignals([]byte(`{"currentID":"` + id + `"}`))
87 | sse.PatchElements(buf.String(), datastar.WithModeReplace())
88 | }
89 |
90 | // change the datastar version between RC.1 and RC.2 to see the difference in behaviour
91 | const indexHTML = `
92 |
93 |
94 |
95 | Datastar Morph Repro
96 |
97 |
100 |
101 |
102 |
103 | {{range .Customers}}
104 | -
105 | {{.Name}}
106 |
107 | {{end}}
108 |
109 |
110 | {{range .Customers}}
111 |
112 |
113 | {{end}}
114 |
115 |
116 |
Click a name to select. In RC.1, this will generate an alert. In RC.2, it will not.
117 |
118 |
119 |
120 | `
121 |
122 | const navHTML = `{{define "nav"}}
123 |
124 | {{range .Customers}}
125 | -
126 | {{.Name}}
127 |
128 | {{end}}
129 |
130 | {{end}}
131 | `
132 |
--------------------------------------------------------------------------------
/go.sum:
--------------------------------------------------------------------------------
1 | github.com/CAFxX/httpcompression v0.0.9 h1:0ue2X8dOLEpxTm8tt+OdHcgA+gbDge0OqFQWGKSqgrg=
2 | github.com/CAFxX/httpcompression v0.0.9/go.mod h1:XX8oPZA+4IDcfZ0A71Hz0mZsv/YJOgYygkFhizVPilM=
3 | github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
4 | github.com/andybalholm/brotli v1.1.1 h1:PR2pgnyFznKEugtsUo0xLdDop5SKXd5Qf5ysW+7XdTA=
5 | github.com/andybalholm/brotli v1.1.1/go.mod h1:05ib4cKhjx3OQYUY22hTVd34Bc8upXjOLL2rKwwZBoA=
6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
7 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
8 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
9 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
10 | github.com/google/brotli/go/cbrotli v0.0.0-20230829110029-ed738e842d2f h1:jopqB+UTSdJGEJT8tEqYyE29zN91fi2827oLET8tl7k=
11 | github.com/google/brotli/go/cbrotli v0.0.0-20230829110029-ed738e842d2f/go.mod h1:nOPhAkwVliJdNTkj3gXpljmWhjc4wCaVqbMJcPKWP4s=
12 | github.com/klauspost/compress v1.16.7/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
13 | github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
14 | github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
15 | github.com/klauspost/pgzip v1.2.6/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs=
16 | github.com/pierrec/lz4/v4 v4.1.18 h1:xaKrnTkyoqfh1YItXl56+6KJNVYWlEEPuAQW9xsplYQ=
17 | github.com/pierrec/lz4/v4 v4.1.18/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
18 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
19 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
20 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
21 | github.com/starfederation/datastar-go v1.0.1 h1:OimYOKrcSPlt88jfFisUDNR6G78V7U2BKxXNbOoYc0Y=
22 | github.com/starfederation/datastar-go v1.0.1/go.mod h1:fLrkAlMKaiMQpMkDVf+IcmrYVGAXj4pBSbeQo33FJxA=
23 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
24 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
25 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
26 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
27 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
28 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
29 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
30 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
31 | github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
32 | github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
33 | github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
34 | github.com/valyala/gozstd v1.20.1 h1:xPnnnvjmaDDitMFfDxmQ4vpx0+3CdTg2o3lALvXTU/g=
35 | github.com/valyala/gozstd v1.20.1/go.mod h1:y5Ew47GLlP37EkTB+B4s7r6A5rdaeB7ftbl9zoYiIPQ=
36 | github.com/xyproto/randomstring v1.0.5 h1:YtlWPoRdgMu3NZtP45drfy1GKoojuR7hmRcnhZqKjWU=
37 | github.com/xyproto/randomstring v1.0.5/go.mod h1:rgmS5DeNXLivK7YprL0pY+lTuhNQW3iGxZ18UQApw/E=
38 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
39 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
40 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
41 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
42 |
--------------------------------------------------------------------------------