gomodest-template
gomodest-template copied to clipboard
A template to build dynamic web apps quickly using Go, html/template and javascript
gomodest-template
A modest template to build dynamic web apps in Go, HTML and sprinkles and spots of javascript.
Why ?
- Build dynamic websites using the tools you already know(Go, HTML, CSS, Vanilla Javascript) for the most part.
- Use bulma components to speed up prototyping a responsive and good-looking UI.
- Use turbo & stimulusjs for most of the interactivity.
- For really complex interactivity use Svelte for a single div in a few spots.
- Lightweight and productive. Fast development cycle.
- Easy to start, easy to maintain.
For a more complete implementation using this technique please see gomodest-starter.
Usage
- Use as a github template
git clone https://github.com/<user>/<mytemplate>andcd /path/to/your/gomodest-templatemake watch(starts hot-reload for go, html and javascript changes)- open localhost:3000.
or
brew install gh
gh repo create myapp --template adnaan/gomodest-template
cd myapp
make install # or (make install-x64)
# replace gomodest-template with your app name
go get github.com/piranha/goreplace
$(go env GOPATH)/bin/goreplace gomodest-template -r myapp
git add . && git commit -m "replace gomodest-template"
make watch # or make watch-x64

TOC
- Folder Structure
- Views using html templates
- Step 1: Add a layout partial
- Step 2: Add a layout
- Step 4: Add a view partial
- Step 5: Add a view
- Step 6: Render view
- Interactivity using Javascript
- Stimulus Controllers
- Step 1: Add a controller
- Step 2: Add data attributes to the target div
- Svelte Components
- Step 1: Add data attributes to the target div.
- Step 2: Create and export svelte component
- Step 3: Hydrate initial props from the server
- Stimulus Controllers
- Styling and Images
- Samples
- Dependencies
Table of contents generated with markdown-toc
Folder Structure
-
templates/
- layouts/
- partials/
- list of view files
-
assets/
-
images/
-
src/
- components/
- controllers/
- index.js
- styles.scss
-
-
templatesis the root directory where all html/templates assets are found. -
layoutscontains the layout files. Layout is a container forpartialsandview files -
partialscontains the partial files. Partial is a reusable html template which can be used in one of two ways:-
Included in a
layoutfile:{{include "partials/header"}} -
Included in a
viewfile:{{template "main" .}}. When used in a view file, a partial must be enclosed in adefinetag:{{define "main"}} Hello {{.hello}} {{end}}
-
-
viewfiles are put in the root of thetemplatesdirectory. They are contained within alayoutmust be enclosed in adefine contenttag:{{define "content"}} App's {{.dashboard}} {{end}}Viewis rendered within alayout:indexLayout, err := rl.New( rl.Layout("index"), rl.DisableCache(true), rl.DefaultHandler(func(w http.ResponseWriter, r *http.Request) (rl.M, error) { return rl.M{ "app_name": "gomdest-template", }, nil })) ... r.Get("/", indexLayout.Handle("home", func(w http.ResponseWriter, r *http.Request) (rl.M, error) { return rl.M{ "hello": "world", }, nil }))Here the
view:homeis rendered within theindexlayout.
Please see the templates directory.
-
assetsdirectory contains the public asset pipeline for the project.styles.scssis a customscssfile for [bulma][https://bulma.io] as documented here.index.jsis the entrypoint for loadingstimulusjscontrollers sourced from this [example](https://github.com/hotwired/stimulus-starter.controllerscontains stimulusjs controllers.componentscontains single file svelte components.
Views using html templates
There are three kinds of html/template files in this project.
layout: defines the base structure of a web page.partial: reusable snippets of html. It can be of two types:layout partials&view partials.view: the main container for the web page logic contained within alayout. It must be enclosed in adefine contenttemplate definition. It can use view partials.
Step 1: Add a layout partial
Create header.html file in templates/partials.
<meta charset="UTF-8">
<meta name="description" content="A modest way to build golang web apps">
<meta name="viewport"content="width=device-width, initial-scale=1.0, maximum-scale=5.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
...
Step 2: Add a layout
Create index.html file in templates/layouts and use the above partial.
<!DOCTYPE html>
<html lang="en">
<head>
<title>{{.app_name}}</title>
{{include "partials/header"}}
</head>
<body ...>
...
</body>
</html>
Step 4: Add a view partial
Create main.html in templates/partials
{{define "main"}}
<main>
<div class="columns is-centered is-vcentered is-mobile py-5">
<div class="column is-narrow" style="width: 70%">
<h1 class="has-text-centered title">Hello {{.hello}}</h1>
</div>
</div>
</main>
{{end}}
This is a different from the layout partial since it's closed in a define tag.
Step 5: Add a view
Create home.html in templates and use the above partial.
{{define "content"}}
<div class="columns is-mobile is-centered">
<div class="column is-half-desktop">
{{template "main" .}}
</div>
</div>
{{end}}
Notice that a view is always enclosed in define content template definition.
Step 6: Render view
To render the view with data we use a wrapper over the html/template package.
r.Get("/", indexLayout.Handle("home",
func(w http.ResponseWriter, r *http.Request) (rl.M, error) {
return rl.M{
"hello": "world",
}, nil
}))
To learn more about html/template, please look into this amazing cheatsheet.
Reference:
templates/layout/index.htmltemplates/partials/header.htmltemplates/partials/main.htmltemplates/home.htmlmain.go
Interactivity using Javascript
For client-side interactivity we use a bit of javascript.
Stimulus Controllers
A stimulus controller is a snippet of javascript which handles a single aspect of interactivity. To add a new svelte component:
Step 1: Add a controller
Create a file with suffix: _controller.js
util_controller.js
import { Controller } from "stimulus"
export default class extends Controller {
...
connect(){
}
goto(e){
if (e.currentTarget.dataset.goto){
window.location = e.currentTarget.dataset.goto;
}
}
goback(e){
window.history.back();
}
...
}
See complete implementation in assets/src/controller/util_controller.js. To understand how stimulus works, please see the handbook.
Step 2: Add data attributes to the target div
<body data-controller="util svelte"
data-action="keydown@window->util#keyDown "
data-util-active-class="is-active">
...
<button class="button"
data-action="click->util#goto"
data-goto="/">Home
</button>
</body>
Here we are attaching two controllers to the body itself since they are used often. Later we can add action and data attributes to use them.
Reference:
templates/layout/index.htmltemplates/404.htmlassets/src/controllers/util_controller.js
Svelte Components
A svelte component is loaded into the targeted div by a stimulujs controller: controllers/svelte_controller.js. This is hooked by declaring data attributes on the div which is to be contain the svelte component:
-
data-svelte-target: Value is required to becomponent. It's used for identifying the divs as targets for thesvelte_controller. -
data-component-name: The name of the component as exported insrc/components/index.jsimport app from "./App.svelte" // export other components here. export default { app: app, } -
data-component-props: A string map object which is passed as initial props to the svelte component.
To add a new svelte component:
Step 1: Add data attributes to the target div.
{{define "content"}}
<div class="columns is-mobile is-centered">
<div class="column is-half-desktop">
<div
data-svelte-target="component"
data-component-name="app"
data-component-props="{{.Data}}">
</div>
</div>
</div>
</div>
{{end}}
Step 2: Create and export svelte component
- Create a new svelte component in
src/componentsand export it insrc/components/index.js
import app from "./App.svelte"
// export other components here.
export default {
app: app,
}
The controllers/svelte_controller.js controller loads the svelte component in to the div with the required data attributes shown in step 1.
Step 3: Hydrate initial props from the server
It's possible to hydrate initial props from the server and pass onto the component. This is done by templating a string data object into the data-component-props attribute.
r.Get("/app", indexLayout.Handle("app",
func(w http.ResponseWriter, r *http.Request) (rl.M, error) {
appData := struct {
Title string `json:"title"`
}{
Title: "Hello from server for the svelte component",
}
d, err := json.Marshal(&appData)
if err != nil {
return nil, fmt.Errorf("%v: %w", err, fmt.Errorf("encoding failed"))
}
return rl.M{
"Data": string(d), // notice struct data is converted into a string
}, nil
}))
Reference:
templates/app.htmlsrc/controllers/svelte_controller.jssrc/components/*main.go
Styling and Images
Bulma is included by default. Bulma is a productive css framework with prebuilt components and helper utilities.
assets/src/styles.scss: to override default bulma variables.webpackbundles and copies css assets to `public/assets/css.assets/images: put image assets here. it will be auto-copied topublic/assets/imagesbywebpack.
Samples
Go to localhost:3000/samples to a list of sample views. Copy-paste at will from the templates/samples directory.