Files
iris/host/README.md
Hugo Nijhuis 89efc9b41d Add hot reload for development
Implement automatic rebuild and browser reload during development:

- File watcher monitors .go files for changes with configurable extensions
- Builder compiles Go source to WASM on file changes
- LiveReload WebSocket server notifies connected browsers to reload
- DevServer combines all components for easy development setup
- HTML injection adds reload script automatically

Usage:
  dev := host.NewDevServer("public", "index.html", ".", "public/app.wasm")
  dev.ListenAndServe(":8080")

Closes #9

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 16:34:16 +00:00

202 lines
4.4 KiB
Markdown

# Host Package
Static file server optimized for serving Iris WASM applications.
## Basic Setup
```go
package main
import (
"log"
"net/http"
"git.flowmade.one/flowmade-one/iris/host"
)
func main() {
server := host.New("public", "index.html")
log.Println("Server running on http://localhost:8080")
log.Fatal(http.ListenAndServe(":8080", server))
}
```
## Directory Structure
```
myapp/
├── server.go # Server code (above)
└── public/
├── index.html # Entry point
├── app.wasm # Compiled WASM binary
└── wasm_exec.js # Go WASM runtime
```
## Serving Static Files
The server serves files from the specified public directory. Any request path maps directly to files:
- `/` -> `public/index.html`
- `/app.wasm` -> `public/app.wasm`
- `/styles.css` -> `public/styles.css`
**SPA Fallback**: Unknown paths and directories fall back to `index.html`, enabling client-side routing.
## WASM MIME Types
The server automatically sets correct MIME types for all common file types:
| Extension | MIME Type |
|-----------|-----------|
| `.wasm` | `application/wasm` |
| `.html` | `text/html; charset=utf-8` |
| `.js` | `application/javascript` |
| `.css` | `text/css` |
| `.json` | `application/json` |
| `.svg` | `image/svg+xml` |
This ensures browsers load WASM files correctly without manual configuration.
## Compression
Gzip compression is automatically applied to compressible content types when the client supports it:
- HTML, CSS, JavaScript
- JSON
- WASM binaries
- SVG images
Binary assets (PNG, JPEG, etc.) are served uncompressed since they're already compressed.
## Hot Reload (Development)
The `DevServer` provides automatic rebuild and browser reload during development:
```go
package main
import (
"git.flowmade.one/flowmade-one/iris/host"
)
func main() {
// Create dev server with hot reload
dev := host.NewDevServer(
"public", // Static files directory
"index.html", // Index file
".", // Source directory to watch
"public/app.wasm", // WASM output path
)
// Start watching and serving
dev.ListenAndServe(":8080")
}
```
### How It Works
1. **File Watcher**: Monitors `.go` files in the source directory for changes
2. **Auto Build**: Runs `GOOS=js GOARCH=wasm go build` when changes are detected
3. **Browser Reload**: Injects a WebSocket client into HTML pages that triggers reload on build success
### Directory Structure for Development
```
myapp/
├── main.go # WASM application entry point
├── server/
│ └── main.go # Dev server (code above)
└── public/
├── index.html
├── app.wasm # Generated by dev server
└── wasm_exec.js
```
### Workflow
1. Start the dev server: `go run ./server`
2. Open `http://localhost:8080` in your browser
3. Edit your Go source files
4. Save - the browser automatically reloads with your changes
### Custom Watch Configuration
```go
// Watch additional file types
watcher := host.NewWatcher(
".",
onChangeCallback,
host.WithExtensions(".go", ".html", ".css"),
host.WithInterval(100*time.Millisecond),
)
```
### Manual Components
For advanced use cases, you can use the individual components:
```go
// File watcher
watcher := host.NewWatcher(".", func() {
log.Println("Files changed")
})
watcher.Start()
defer watcher.Stop()
// WASM builder
builder := host.NewBuilder(".", "public/app.wasm")
result := builder.Build()
if result.Success {
log.Println("Build succeeded")
}
// Live reload (WebSocket notifications)
lr := host.NewLiveReload()
http.Handle("/__livereload", lr)
lr.NotifyReload() // Triggers reload in all connected browsers
```
## Production
For production, use the standard `Server` instead of `DevServer`:
```go
func main() {
server := host.New("public", "index.html")
log.Fatal(http.ListenAndServe(":8080", server))
}
```
Compile and deploy:
```bash
go build -o server ./server
./server
```
Consider adding:
- TLS termination (via reverse proxy or `http.ListenAndServeTLS`)
- Environment-based port configuration
- Graceful shutdown handling
Example with TLS:
```go
func main() {
server := host.New("public", "index.html")
log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", server))
}
```
Example with reverse proxy (nginx):
```nginx
server {
listen 443 ssl;
server_name example.com;
location / {
proxy_pass http://localhost:8080;
proxy_set_header Host $host;
}
}
```