Replies: 4 comments 7 replies
-
|
Agreed! "Static website with a smattering of dynamic features" is exactly what I had in mind when creating xtemplate, and "Hugo++" is a great way to describe it. |
Beta Was this translation helpful? Give feedback.
-
|
I still have a nagging idea that maybe xtemplate can be taken a lot farther and used to create app-like experiences (note the database, NATS, SSE features). I started an experiment last year with infogulch/xrss but it was never polished past a tech demo and xtemplate has made some breaking changes since then. I'm sure it "can be done" but the real question is "is it worth it compared to other options"; in particular the "initial development rate" and "long term maintenance" and "level of experience" will be the interesting metrics to look for. My suspicion is that xtemplate can be viable much further into "app" territory than where most people might guess. |
Beta Was this translation helpful? Give feedback.
-
|
Yeah you're absolutely right. And yeah - I'm not really building app functionally, but I've found it does everything I need and more. I've been building a simple comparison site with it for fun and I've been able to do everything that I wanted - really easily.
Datastar works nicely as well using SSE - just doing some simple swaps (there may be a nicer way of doing this but works!) <html>
<title>Some site</title>
<body>
<div id="content">Original</div>
<button data-on-click="@get('/some-url')">Some button</button>
</body>
</html>{{- define "SSE /some-url" }}
{{- $frag := cat "fragments" (.X.Template "some-html" nil) }}
{{- .Flush.SendSSE "datastar-merge-fragments" $frag }}
{{- end }}
{{- define "some-html" -}}
<div id="content">Updated!</div>
{{- end -}}Also getting an admin up and running was simple using just basic auth (site would be over ssl behind caddy so basic auth is likely fine as far as i know) {{ define "basic-auth" }}
{{ if eq (basicAuth .Req) false }}
{{ .Resp.SetStatus 401 }}
{{ .Resp.SetHeader "WWW-Authenticate" `Basic realm="Restricted"` }}
{{ template "/401.html" }}
{{ return }}
{{ end }}
{{ end }}And the function /*
Borrowed from this excellent article
https://www.alexedwards.net/blog/basic-authentication-in-go
*/
func basicAuth(r xtemplate.DotReq) bool {
username, password, ok := r.BasicAuth()
if ok {
// Calculate SHA-256 hashes for the provided and expected
// usernames and passwords.
usernameHash := sha256.Sum256([]byte(username))
passwordHash := sha256.Sum256([]byte(password))
expectedUsernameHash := sha256.Sum256([]byte(os.Getenv("APP_USER")))
expectedPasswordHash := sha256.Sum256([]byte(os.Getenv("APP_USER_PASSWORD")))
// Use the subtle.ConstantTimeCompare() function to check if
// the provided username and password hashes equal the
// expected username and password hashes. ConstantTimeCompare
// will return 1 if the values are equal, or 0 otherwise.
// Importantly, we should to do the work to evaluate both the
// username and password before checking the return values to
// avoid leaking information.
usernameMatch := (subtle.ConstantTimeCompare(usernameHash[:], expectedUsernameHash[:]) == 1)
passwordMatch := (subtle.ConstantTimeCompare(passwordHash[:], expectedPasswordHash[:]) == 1)
// If the username and password are correct, then call
// the next handler in the chain. Make sure to return
// afterwards, so that none of the code below is run.
if usernameMatch && passwordMatch {
return true
}
}
return false
}Another cool thing was the file hashes - your example <link rel="stylesheet" href="/css/pico.css" />
{{- with $hash := .X.StaticFileHash `/css/main.css` }}
<link
rel="stylesheet"
href="/css/main.css?hash={{ $hash }}"
integrity="{{ $hash }}"
/>
{{- end }}This has always been a pain for me building sites over the years! Bottom line, I would say for the sites I build - it's more or less perfect. In terms of the metrics you mention
I've only looked at the SSE stuff quickly - but i can see how there are a whole world of app like possibilities there. Fantastic! What is NATS by the way?? |
Beta Was this translation helpful? Give feedback.
-
|
You know I bet this could be easier... <link rel="stylesheet" href="/css/pico.css" />
{{- with $hash := .X.StaticFileHash `/css/main.css` }}
<link
rel="stylesheet"
href="/css/main.css?hash={{ $hash }}"
integrity="{{ $hash }}"
/>
{{- end }}...with something like this: <!-- in any file: -->
{{- define "link-stylesheet"}}
{{- with $hash := .X.StaticFileHash . }}
<link rel="stylesheet" href="{{ . }}?hash={{ $hash }}" integrity="{{ $hash }}" />
{{- end}}
{{- end}}
<!-- later... -->
{{template "link-stylesheet" "/css/pico.css"}}
{{template "link-stylesheet" "/css/main.css"}}Edit: Wait no that won't work. I keep forgetting that if you override Ok its a bit messier than I'd want but this actually works now and is more general, though vulnerable if the attribute names are set dynamically. {{- define "link"}}
{{- $dot := .dot}}{{$_ := unset . "dot"}}
{{- $href := .href}}{{$_ := unset . "href" }}
{{- $hash := $dot.X.StaticFileHash $href }}
<link href="{{ $href }}?hash={{ $hash }}" integrity="{{ $hash }}"{{range $k,$v := .}} {{$k | trustAttr}}="{{$v}}"{{end}}/>
{{- end}}
{{- template "link" (dict "dot" . "href" "/assets/reset.css" "rel" "stylesheet")}}
{{- template "link" (dict "dot" . "href" "/assets/print.css" "rel" "stylesheet" "media" "print")}} |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Lots of people out there have built Hugo sites but invariably hit a snag where they want to add some dynamic content. Xtemplate seems almost perfect for porting static sites that have hit the limits of what you can do with the static model - so you can add forms, tracking etc, all the dynamic bits that sites inevitably end up needing.
I've not attempted it but I would imagine migrating a simpler Hugo site to xtemplate would be fairly straightforward.
Probably not an original idea but I thought it was worth mentioning :)
Beta Was this translation helpful? Give feedback.
All reactions