Go Component WIT World Limitations - TinyGo Hardcoded to wasi:cli/command
Closed this issue ยท 2 comments
Problem Summary
Our Go WebAssembly components using go_wasm_component are currently limited to the wasi:cli/command world, preventing the creation of custom WIT interface exports. This means we can only build WASI CLI applications, not true WIT-defined component interfaces with custom functions like add(), subtract(), etc.
Root Cause Analysis
The issue stems from upstream TinyGo limitations rather than our Bazel rules implementation. TinyGo currently hardcodes the WASI command world and cannot handle custom WIT worlds properly.
Current Behavior
When we try to build Go components with custom WIT interfaces:
go_wasm_component(
name = "calculator_simple_binding",
srcs = ["calculator_simple_binding.go"],
go_mod = "go.mod",
wit = ":simple_calculator_wit",
world = "calculator-world",
)The resulting component exports wasi:cli/command@0.2.0 instead of our intended example:calculator/calculator@1.0.0 interface.
Technical Details
The TinyGo compilation process ignores custom --wit-world parameters:
tinygo build -target=wasip2 -o calculator.wasm \
--wit-package wit/simple-calculator.wit \
--wit-world calculator-world .This produces a component that validates against WASI CLI expectations rather than custom WIT interfaces.
Upstream TinyGo Issues
This limitation is documented in several TinyGo repository issues:
- Issue #4843: "Support for custom WIT worlds" - Core limitation preventing custom interface definitions
- Issue #4587: "WASI Preview 2 custom interfaces" - Discusses the hardcoded world limitation
- Issue #4752: "WIT binding generation improvements" - Related to proper WIT interface handling
- PR #4934: "Add support for custom WIT worlds in wasip2 target" - THE SOLUTION
Impact on rules_wasm_component
This upstream limitation affects our ability to:
- Create true WebAssembly Component Model interfaces in Go
- Build components that export custom functions rather than CLI commands
- Integrate Go components with other language components via WIT interfaces
- Demonstrate complete Component Model capabilities in our examples
Current Workaround
Our current implementation correctly:
- Integrates
wit-bindgen-gofor binding generation - Passes WIT files and world parameters to TinyGo
- Generates proper Go binding structures
However, TinyGo itself ignores the custom world specification and defaults to wasi:cli/command.
Next Steps
- Monitor TinyGo PR #4934 - This PR specifically addresses custom WIT world support
- Test with TinyGo development builds once the PR is merged
- Update our TinyGo toolchain version when a release includes this functionality
- Add integration tests for custom WIT world validation once upstream support is available
Verification Command
To verify component exports:
wasm-tools component wit component.wasmCurrently shows wasi:cli/command@0.2.0 instead of custom interfaces.
References
- TinyGo Issue #4843
- TinyGo Issue #4587
- TinyGo Issue #4752
- TinyGo PR #4934 - Solution in progress
This issue will be resolved once TinyGo adds proper custom WIT world support in their wasip2 target implementation.
๐ RESOLVED - Custom WIT Worlds Already Supported!
Major Update (Oct 2025): This issue is based on a misunderstanding. TinyGo already supports custom WIT worlds without any code changes needed!
How It Works
TinyGo's -wit-world flag overrides the default wasi:cli/command world:
tinygo build -target=wasip2 \
-wit-package=wit/calculator.wit \
-wit-world=calculator-world \
-o calculator.wasm main.goThe default in wasip2.json is only used when -wit-world is not specified.
Evidence
- TinyGo PR #4934: Closed Oct 6, 2025 as "not needed"
- TinyGo Issue #4843: Confirmed by @cataggar that custom worlds work via
-wit-worldflag - Code Reference: builder/build.go:921-938
Action Items
- Update our
go_wasm_componentrule to pass-wit-worldparameter correctly - Test with calculator example to verify custom interface exports
- Validate component output with
wasm-tools component wit
References
This means we can create true WebAssembly Component Model interfaces in Go right now! ๐
โ COMPLETE SOLUTION IMPLEMENTED
Status: Custom WIT worlds are fully supported with correct flag usage and composition architecture.
Code Fixes Completed (go/defs.bzl)
-
Flag Format (line 406-415):
- Changed
--wit-packageโ-wit-package(single-dash) - Changed
--wit-worldโ-wit-world(single-dash)
- Changed
-
WIT Directory Path:
- Pass full WIT library directory (with
deps/structure) - Enables proper WASI dependency resolution
- Pass full WIT library directory (with
-
Absolute Path Resolution (line 567-587):
- WIT package path made absolute in wrapper script
- Fixes execution context issues
Architecture: Component Composition
For Multi-Component Systems (Rust main + Go library):
// WAC composition example
let rust_main = new cli:component { ... };
let go_calc = new calculator:component { ... };
// Link: Rust imports calculator โ Go exports calculator
connect rust_main.calculator_request -> go_calc.calculate;
// Host provides WASI to both
export rust_main as main;
Import Resolution:
- Rust main: imports
wasi:cli/command+example:calculator - Go reactor: imports
wasi:io/streams, exportscalculator - Composed result: Only
wasi:cli/*andwasi:io/*from host
Go Reactor Pattern
package main
func main() {} // Empty for reactor mode
//export example_calculator_add
func add(a, b float64) float64 { return a + b }Key Finding: TinyGo reactors need minimal WASI (wasi:io/streams) even with empty main(). This is a TinyGo runtime requirement, not a limitation.
Documentation
Complete composition guide: examples/go_component/COMPOSITION_GUIDE.md
References
- TinyGo Issue #2703 - Reactor mode support
- TinyGo Issue #4843 - Custom worlds confirmed working
- Component Model Docs
Resolution: Working as designed. Use WAC/wasm-tools for multi-component composition.