refactor: simplify Datastar configuration API

Flatten DatastarConfig struct into Options (DatastarContent, DatastarPath)
and replace datastarHandlerRegistered bool with sync.Once for thread safety.
This commit is contained in:
Ryan Hamamura
2026-01-14 02:01:18 -10:00
parent ea7b9ad4a1
commit d4b831492e
3 changed files with 23 additions and 38 deletions

View File

@@ -2,17 +2,6 @@ package via
import "github.com/alexedwards/scs/v2" import "github.com/alexedwards/scs/v2"
// DatastarConfig configures a custom Datastar.js script.
type DatastarConfig struct {
// Content is the Datastar.js script content.
// If nil, the embedded default is used.
Content []byte
// Path is the URL path where the script is served.
// Defaults to "/_datastar.js" if empty.
Path string
}
type LogLevel int type LogLevel int
const ( const (
@@ -49,7 +38,11 @@ type Options struct {
// passing it (lifetime, cookie settings, store, etc). // passing it (lifetime, cookie settings, store, etc).
SessionManager *scs.SessionManager SessionManager *scs.SessionManager
// Datastar configures a custom Datastar.js script. // DatastarContent is the Datastar.js script content.
// If nil, Via uses its embedded default. // If nil, the embedded default is used.
Datastar *DatastarConfig DatastarContent []byte
// DatastarPath is the URL path where the script is served.
// Defaults to "/_datastar.js" if empty.
DatastarPath string
} }

18
via.go
View File

@@ -42,7 +42,7 @@ type V struct {
sessionManager *scs.SessionManager sessionManager *scs.SessionManager
datastarPath string datastarPath string
datastarContent []byte datastarContent []byte
datastarHandlerRegistered bool datastarOnce sync.Once
} }
func (v *V) logFatal(format string, a ...any) { func (v *V) logFatal(format string, a ...any) {
@@ -111,13 +111,11 @@ func (v *V) Config(cfg Options) {
if cfg.SessionManager != nil { if cfg.SessionManager != nil {
v.sessionManager = cfg.SessionManager v.sessionManager = cfg.SessionManager
} }
if cfg.Datastar != nil { if cfg.DatastarContent != nil {
if cfg.Datastar.Content != nil { v.datastarContent = cfg.DatastarContent
v.datastarContent = cfg.Datastar.Content
}
if cfg.Datastar.Path != "" {
v.datastarPath = cfg.Datastar.Path
} }
if cfg.DatastarPath != "" {
v.datastarPath = cfg.DatastarPath
} }
} }
@@ -271,14 +269,12 @@ func (v *V) HTTPServeMux() *http.ServeMux {
} }
func (v *V) ensureDatastarHandler() { func (v *V) ensureDatastarHandler() {
if v.datastarHandlerRegistered { v.datastarOnce.Do(func() {
return
}
v.datastarHandlerRegistered = true
v.mux.HandleFunc("GET "+v.datastarPath, func(w http.ResponseWriter, r *http.Request) { v.mux.HandleFunc("GET "+v.datastarPath, func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/javascript") w.Header().Set("Content-Type", "application/javascript")
_, _ = w.Write(v.datastarContent) _, _ = w.Write(v.datastarContent)
}) })
})
} }
func (v *V) devModePersist(c *Context) { func (v *V) devModePersist(c *Context) {

View File

@@ -45,9 +45,7 @@ func TestCustomDatastarContent(t *testing.T) {
customScript := []byte("// Custom Datastar Script") customScript := []byte("// Custom Datastar Script")
v := New() v := New()
v.Config(Options{ v.Config(Options{
Datastar: &DatastarConfig{ DatastarContent: customScript,
Content: customScript,
},
}) })
v.Page("/", func(c *Context) { v.Page("/", func(c *Context) {
c.View(func() h.H { return h.Div() }) c.View(func() h.H { return h.Div() })
@@ -65,9 +63,7 @@ func TestCustomDatastarContent(t *testing.T) {
func TestCustomDatastarPath(t *testing.T) { func TestCustomDatastarPath(t *testing.T) {
v := New() v := New()
v.Config(Options{ v.Config(Options{
Datastar: &DatastarConfig{ DatastarPath: "/assets/datastar.js",
Path: "/assets/datastar.js",
},
}) })
v.Page("/test", func(c *Context) { v.Page("/test", func(c *Context) {
c.View(func() h.H { return h.Div() }) c.View(func() h.H { return h.Div() })