Go package for intelligent WebAssembly compilation with automatic file detection and 3-mode compiler system.
- 3-Mode Compiler System: Large ("L"), Medium ("M"), Small ("S")
- DevTUI Integration: FieldHandler interface for interactive mode switching
- Smart file detection via prefixes (frontend/backend separation)
- Triple compiler support: Go standard (fast dev), TinyGo debug (-opt=1), TinyGo production (-opt=z)
- VS Code auto-configuration for WASM development
- Dual Output Architecture: WASM binaries in
src/web/public/, watchable JS insrc/web/ui/js/
// Basic usage
config := tinywasm.NewConfig() // Pre-configured with defaults
config.SourceDir = "src/cmd/webclient"
config.OutputDir = "src/web/public"
config.WasmExecJsOutputDir = "src/web/ui/js"
tw := tinywasm.New(config)
tw.NewFileEvent("src/cmd/webclient/main.go", ".go", "src/cmd/webclient/main.go", "write")
// DevTUI Integration - 3 Mode System
fmt.Println("Current mode:", tw.Value()) // "L" (coding / large build)
// New API: Change now reports progress via a channel instead of returning (msg, err).
// Create and consume a progress channel before calling Change to avoid blocking.
progress := make(chan string)
go func() {
for p := range progress {
fmt.Println("Status:", p)
}
}()
tw.Change("M", progress) // Switch to medium (debug) mode; messages arrive on the progress channel
// Advanced configuration
config := &tinywasm.Config{
AppRootDir: "/path/to/project",
SourceDir: "src/cmd/webclient",
OutputDir: "src/web/public",
WasmExecJsOutputDir: "src/web/ui/js",
MainInputFile: "main.go",
OutputName: "main",
BuildLargeSizeShortcut: "L", // Customizable shortcuts (default: L = Large/fast with go)
BuildMediumSizeShortcut: "M",
BuildSmallSizeShortcut: "S",
Logger: logger,
}TinyWasm implements the DevTUI FieldHandler interface for interactive development:
// DevTUI Integration
label := tw.Label() // "Compiler Mode"
current := tw.Value() // Current mode shortcut ("L", "M", "S")
canEdit := tw.Editable() // true
timeout := tw.Timeout() // 0 (no timeout)
// Interactive mode change with the new Change API
// Change now has signature: Change(newValue string, progress chan<- string)
// All validation messages, warnings (e.g. auto-compilation failed) and success
// messages are sent through the provided channel. The channel is closed when
// the operation completes.
progress := make(chan string)
go func() {
for p := range progress {
// Handle progress messages (show in TUI, log, etc.)
fmt.Println("Progress:", p)
}
}()
tw.Change("M", progress)
// No return values; read errors and status from the progress channel above.Auto-creates .vscode/settings.json with WASM environment:
{"gopls": {"env": {"GOOS": "js", "GOARCH": "wasm"}}}Core:
New(config *Config) *TinyWasmNewConfig() *Config- Pre-configured with sensible defaultsNewFileEvent(fileName, ext, path, event string) errorShouldCompileToWasm(fileName, path string) bool
DevTUI FieldHandler Interface:
Label() string- Returns "Compiler Mode"Value() string- Current mode shortcut ("L", "M", "S")Editable() bool- Returns true (field is editable)Change(newValue string, progress chan<- string)- Switch compiler mode and report progress via the provided channel. Validation errors, auto-compilation warnings and success messages are sent to the channel; the implemention closes the channel when finished.Timeout() time.Duration- Returns 0 (no timeout)
Legacy Compiler Methods (deprecated):
TinyGoCompiler() bool- UseValue()insteadSetTinyGoCompiler(bool) error- UseChange()insteadVerifyTinyGoInstallation() error
Utils:
MainInputFileRelativePath() stringUnobservedFiles() []stringJavascriptForInitializing() (string, error)
type Config struct {
AppRootDir string // application root directory (absolute), defaults to "."
SourceDir string // directory containing Go source (relative) eg: "src/cmd/webclient"
OutputDir string // directory for WASM binary output (relative) eg: "src/web/public"
WasmExecJsOutputDir string // directory for watchable JS runtime (relative) eg: "src/web/ui/js"
MainInputFile string // main input file for WASM compilation (default: "main.go")
OutputName string // output name for WASM file (default: "main")
Logger func(message ...any) // For logging output to external systems (e.g., TUI, console)
// NEW: Shortcut configuration (default: "f", "b", "m")
BuildLargeSizeShortcut string // "L" (large/fast) compile fast with go
BuildMediumSizeShortcut string // "M" (medium/debug) compile with tinygo debug
BuildSmallSizeShortcut string // "S" (small/minimal) compile with tinygo minimal binary size
// gobuild integration fields
Callback func(error) // Optional callback for async compilation
CompilingArguments func() []string // Build arguments for compilation (e.g., ldflags)
// DisableWasmExecJsOutput prevents automatic creation of wasm_exec.js file
// Useful when embedding wasm_exec.js content inline (e.g., Cloudflare Pages Advanced Mode)
DisableWasmExecJsOutput bool
}
// Pre-configured constructor (recommended)
func NewConfig() *ConfigTinyWasm produces two types of outputs that serve different purposes in the build pipeline:
- Location:
src/web/public/main.wasm - Purpose: Final compiled WebAssembly binary loaded by the browser
- Consumed by: Browser at runtime
- Modes: All three compilation modes produce output here
- Location:
src/web/ui/js/wasm_exec.js - Purpose: Mode-specific JavaScript runtime that:
- Informs external tools about the current compilation mode (Go vs TinyGo)
- Triggers file watchers to reload the browser when mode changes
- Gets compiled together with other JavaScript by external asset bundlers
- Consumed by: File watchers (e.g.,
devwatch) and asset bundlers (e.g.,assetmin) - Important: TinyWasm's only responsibility is writing the correct
wasm_exec.jsaccording to the active mode. External tools handle final bundling.
- Separation of Concerns: Runtime assets vs. build-time integration
- Build Pipeline Integration: File watchers track
wasm_exec.jschanges - No Dev/Prod States: All modes use the same directories
- Mode Transparency: External tools detect mode changes via
wasm_exec.js
// Example usage with the new channel-based Change API:
progress := make(chan string)
go func() {
for p := range progress {
fmt.Println(p)
}
}()
tw.Change("S", progress) // production mode with TinyGo -opt=z
// Repeat for other modes as needed (always provide and consume a progress channel)
// tw.Change("M", progress)
// tw.Change("L", progress)- Go 1.20+
- TinyGo (optional, required for debug/production modes)
- DevTUI (optional, for interactive development)
Benefits:
- 🎯 3 optimized modes instead of binary choice
- 🔧 DevTUI integration for interactive development
- 📦 Smaller debug builds with TinyGo -opt=1
- ⚡ Auto-recompilation on mode switch
- 🛠️ Better error handling with validation
- 🏗️ Dual output architecture for better build pipeline integration