Files
Hugo Nijhuis 341379c166
All checks were successful
CI / build (pull_request) Successful in 27s
Remove unused responseWriter struct
Address review feedback to remove dead code.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-09 17:23:09 +01:00
..
2026-01-09 17:03:28 +01:00
2026-01-09 17:03:28 +01:00
2026-01-09 17:03:28 +01:00
2026-01-09 17:03:28 +01:00
2026-01-09 17:03:28 +01:00
2026-01-08 19:23:49 +01:00
2026-01-09 17:03:28 +01:00
2026-01-09 17:03:28 +01:00

Host Package

Static file server optimized for serving Iris WASM applications.

Basic Setup

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:

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

// 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:

// 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:

func main() {
	server := host.New("public", "index.html")
	log.Fatal(http.ListenAndServe(":8080", server))
}

Compile and deploy:

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:

func main() {
	server := host.New("public", "index.html")
	log.Fatal(http.ListenAndServeTLS(":443", "cert.pem", "key.pem", server))
}

Example with reverse proxy (nginx):

server {
    listen 443 ssl;
    server_name example.com;

    location / {
        proxy_pass http://localhost:8080;
        proxy_set_header Host $host;
    }
}