GOMODEST
GOMODEST is a toy Multi Page App(MPA) using Go's html/template, SvelteJS and StimulusJS. It is inspired from modest approaches to building webapps as enlisted in https://modestjs.works/. It can be used as a template to spin off simple Go webapps.
Stack
A few things which were used:
- Go, html/template, goview
- SvelteJS
- StimulusJS
- Bulma CSS
Many more things in go.mod
& web/package.json
To run, clone this repo and:
$ cd web && yarn install && yarn watch
# another terminal
$ go run main.go
The ideas in this demo app follow the JS gradient as noted here. I have taken the liberty to organise them into the following big blocks: server-rendered html, sprinkles and spots.
Server Rendered HTML
Use html/template
and goview
to render html pages. It's quite powerful when do you don't need client-side interactions.
example:
func accountPage(w http.ResponseWriter, r *http.Request) (goview.M, error) {
session, err := store.Get(r, "auth-session")
if err != nil {
return nil, fmt.Errorf("%v, %w", err, InternalErr)
}
profileData, ok := session.Values["profile"]
if !ok {
return nil, fmt.Errorf("%v, %w", err, InternalErr)
}
profile, ok := profileData.(map[string]interface{})
if !ok {
return nil, fmt.Errorf("%v, %w", err, InternalErr)
}
return goview.M{
"name": profile["name"],
}, nil
}
Sprinkles
Use stimulusjs
to level up server-rendered html to handle simple interactions like: navigations, form validations etc.
example:
<button class="button is-primary is-outlined is-fullwidth"
data-action="click->navigate#goto"
data-goto="/ "
type="button">
Home
</button>
goto(e){
if (e.currentTarget.dataset.goto){
window.location = e.currentTarget.dataset.goto;
}
}
Spots
Use sveltejs
to take over spots
of a server-rendered html page to provide more complex interactivity without page reloads.
This snippet is the most interesting part of this demo:
{{define "content"}}
<div class="columns is-mobile is-centered">
<div class="column is-half-desktop">
<div
data-target="svelte.component"
data-component-name="app"
data-component-props="{{.Data}}">
</div>
</div>
</div>
</div>
{{end}}
In the above snippet, we use StimulusJS to mount a Svelte component by using the following code:
import { Controller } from "stimulus";
import components from "./components";
export default class extends Controller {
static targets = ["component"]
connect() {
if (this.componentTargets.length > 0){
this.componentTargets.forEach(el => {
const componentName = el.dataset.componentName;
const componentProps = el.dataset.componentProps ? JSON.parse(el.dataset.componentProps): {};
if (!(componentName in components)){
console.log(`svelte component: ${componentName}, not found!`)
return;
}
const app = new components[componentName]({
target: el,
props: componentProps
});
})
}
}
}
This strategy allows us to mix server rendered HTML pages with client side dynamism.
Other possibly interesting aspects could be the layout of web/html and the usage of the super nice goview library to render html in these files:
That is all.