├── 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 | 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 | 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 | --------------------------------------------------------------------------------