Documentation Index Fetch the complete documentation index at: https://docs.go-mizu.dev/llms.txt
Use this file to discover all available pages before exploring further.
The live template combines server-rendered views with WebSocket-powered real-time updates. This structure allows the server to push changes to the browser instantly, without the user needing to refresh. It’s like having a constant conversation between your server and the browser.
Directory Layout
myapp/
├── cmd/server/main.go # Entry point
├── app/server/
│ ├── app.go # Application + live server setup
│ ├── config.go # Configuration
│ └── routes.go # HTTP + WebSocket routes
├── handler/
│ ├── home.go # Static home page
│ └── counter.go # Live counter handler
├── assets/
│ ├── embed.go # Asset embedding
│ ├── css/style.css # Styles
│ └── js/live.js # WebSocket client
├── views/
│ ├── layouts/main.html # Main layout
│ ├── pages/
│ │ ├── home.html # Home page
│ │ └── counter.html # Counter page
│ └── partials/ # Shared partials
├── go.mod
└── .gitignore
Core Files
app/server/app.go
package server
import (
" github.com/go-mizu/mizu "
" github.com/go-mizu/mizu/live "
" github.com/go-mizu/mizu/view "
)
type App struct {
cfg Config
app * mizu . App
engine * view . Engine
liveServer * live . Server
}
func New ( cfg Config ) * App {
a := & App { cfg : cfg }
a . app = mizu . New ()
// View engine for templates
a . engine = view . New ( view . Options {
Root : "views" ,
Layout : "layouts/main" ,
})
a . app . Use ( a . engine . Middleware ())
// Live server for WebSocket
a . liveServer = live . NewServer ( live . Options {
OnConnect : a . onConnect ,
OnMessage : a . onMessage ,
})
a . routes ()
return a
}
func ( a * App ) onConnect ( ctx context . Context , s * live . Session ) error {
// Initialize session state
return nil
}
func ( a * App ) onMessage ( ctx context . Context , s * live . Session , topic string , data [] byte ) {
// Handle incoming messages
}
app/server/routes.go
package server
import " example.com/myapp/handler "
func ( a * App ) routes () {
// Static files
a . app . Mount ( "/static/" , staticHandler ( a . cfg . Dev ))
// Pages
a . app . Get ( "/" , handler . Home ())
a . app . Get ( "/counter" , handler . Counter ( a . engine ))
// WebSocket endpoint
a . app . Mount ( "/ws" , a . liveServer . Handler ())
}
handler/counter.go
package handler
import (
" github.com/go-mizu/mizu "
" github.com/go-mizu/mizu/view "
)
func Counter ( engine * view . Engine ) mizu . Handler {
return func ( c * mizu . Ctx ) error {
return c . Render ( "pages/counter" , map [ string ] any {
"Title" : "Counter" ,
"Count" : 0 ,
})
}
}
assets/js/live.js
// WebSocket client for live updates
class LiveSocket {
constructor ( url ) {
this . url = url ;
this . connect ();
}
connect () {
this . ws = new WebSocket ( this . url );
this . ws . onmessage = ( e ) => this . handleMessage ( e );
this . ws . onclose = () => setTimeout (() => this . connect (), 1000 );
}
send ( topic , data ) {
this . ws . send ( JSON . stringify ({ topic , data }));
}
handleMessage ( event ) {
const { topic , data } = JSON . parse ( event . data );
if ( topic === 'update' ) {
document . getElementById ( 'live-content' ). innerHTML = data ;
}
}
}
// Initialize when DOM ready
document . addEventListener ( 'DOMContentLoaded' , () => {
window . live = new LiveSocket ( 'ws://' + location . host + '/ws' );
});
views/pages/counter.html
{{define "content"}}
< div id = "live-content" >
< h1 > Counter: {{.Count}} </ h1 >
< button onclick = " live . send ('increment', '')" > + </ button >
< button onclick = " live . send ('decrement', '')" > - </ button >
</ div >
< script src = "/static/js/live.js" ></ script >
{{end}}
Message Flow
Page Load - Server renders initial HTML
WebSocket Connect - Client connects to /ws
User Action - Button click calls live.send()
Server Receives - OnMessage handler processes
Server Sends - New HTML sent back
DOM Update - Client replaces content
Next Steps
Tutorial Build a real-time chat
Live Docs Deep dive into live views