An open API service indexing awesome lists of open source software.

https://github.com/tinywasm/client

tinywasm is a lightweight toolbox designed to streamline the compilation of Go packages to WebAssembly (WASM) using the TinyGo compiler.
https://github.com/tinywasm/client

Last synced: 5 months ago
JSON representation

tinywasm is a lightweight toolbox designed to streamline the compilation of Go packages to WebAssembly (WASM) using the TinyGo compiler.

Awesome Lists containing this project

README

          

# tinywasm

Project Badges

Go package for intelligent WebAssembly compilation with automatic file detection and 3-mode compiler system.

## Features

- **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 in `src/web/ui/js/`

## Quick Start

```go
// 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,
}
```

## DevTUI FieldHandler Interface

TinyWasm implements the DevTUI FieldHandler interface for interactive development:

```go
// 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.
```

## VS Code Integration

Auto-creates `.vscode/settings.json` with WASM environment:
```json
{"gopls": {"env": {"GOOS": "js", "GOARCH": "wasm"}}}
```

## API

**Core:**
- `New(config *Config) *TinyWasm`
- `NewConfig() *Config` - Pre-configured with sensible defaults
- `NewFileEvent(fileName, ext, path, event string) error`
- `ShouldCompileToWasm(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` - Use `Value()` instead
- `SetTinyGoCompiler(bool) error` - Use `Change()` instead
- `VerifyTinyGoInstallation() error`

**Utils:**
- `MainInputFileRelativePath() string`
- `UnobservedFiles() []string`
- `JavascriptForInitializing() (string, error)`

## Config

```go
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() *Config
```

## Dual Output Architecture

TinyWasm produces **two types of outputs** that serve different purposes in the build pipeline:

### 1. **WASM Binary Output** (`OutputDir`)
- **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

### 2. **Watchable JavaScript Output** (`WasmExecJsOutputDir`)
- **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.js` according to the active mode. External tools handle final bundling.

### Why Two Separate Directories?

1. **Separation of Concerns:** Runtime assets vs. build-time integration
2. **Build Pipeline Integration:** File watchers track `wasm_exec.js` changes
3. **No Dev/Prod States:** All modes use the same directories
4. **Mode Transparency:** External tools detect mode changes via `wasm_exec.js`

## Mode Switching
```go
// 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)
```

## Requirements

- 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

## [Contributing](https://github.com/tinywasm/cdvelop/blob/main/CONTRIBUTING.md)