GoWebComponents brings the power and simplicity of Go to full-stack web development. Combining React-like component architecture with Go's robustness, it offers a unique approach to building high-performance, type-safe web applications.
- Unified Full-Stack Development: Write both frontend and backend in Go, reducing context switching and enabling seamless type sharing across the entire stack.
- Near-Native Performance: Take advantage of WebAssemblyβs performance, running Go code in the browser with speeds close to native execution for computationally heavy tasks.
- Strong Typing and Reliability: Goβs robust type system helps catch errors at compile time, leading to more reliable and maintainable code.
- Concurrent UI Handling: Efficiently manage multiple frontend operations with Goβs goroutines, ensuring smooth, responsive applications without the need for complex concurrency models.
- Memory Management with Garbage Collection: Goβs built-in garbage collector optimizes memory usage in WebAssembly, simplifying memory management compared to manual handling in other languages.
- Simplified State Management: Manage UI and application state directly in Go with a React-like API, eliminating the need for additional state management libraries.
- Enhanced Security with WASM: WebAssemblyβs sandboxed execution environment, combined with Goβs security features, provides an extra layer of protection against common web vulnerabilities.
- Consistent Development Experience: Develop, debug, and maintain your entire application stack using Go, creating a streamlined development process and unified debugging experience.
- Fast Compilation and Deployment: Benefit from Goβs quick compile times and its easy integration into WASM, speeding up development cycles and reducing iteration times.
- Familiar Component Model: Utilize a React-like API in Go, easing the transition for developers familiar with React while leveraging Goβs simplicity and efficiency.
-
Ensure you have Go 1.22.0 or later installed.
-
Add GoWebComponents to your project:
go get github.com/monstercameron/GoWebComponents@v1.1.0
-
Import in your Go files:
import "github.com/monstercameron/GoWebComponents/fiber"
Here are the five most essential functions you'll use when building with GoWebComponents:
-
createElement(typ interface{}, props map[string]interface{}, children ...interface{}) *Element
- Creates a virtual DOM element.
- Use this to define the structure of your components.
-
Text(content string) *Element
- Creates a text node in the virtual DOM.
- Use this for adding text content within elements.
-
useState[T any](initialValue T) (func() T, func(T))
- Manages state within a component.
- Similar to React's useState, for creating and updating component-level state.
-
useEffect(effect func(), deps []interface{})
- Handles side effects in components.
- Similar to React's useEffect, for performing actions after render or on state changes.
-
render(element *Element, container js.Value)
- Renders a component into a DOM container.
- Typically used to mount the root component of your application.
Let's create a simple todo list to showcase GoWebComponents in action:
package main
import (
"fmt"
"syscall/js"
"github.com/monstercameron/GoWebComponents/fiber"
)
func main() {
fmt.Println("Rendering TodoList")
todoList := func(props map[string]interface{}) *fiber.Element {
todos, setTodos := fiber.useState([]string{})
newTodo, setNewTodo := fiber.useState("")
handleInputChange := func() js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
setNewTodo(args[0].Get("target").Get("value").String())
return nil
})
}
handleAddTodo := func() js.Func {
return js.FuncOf(func(this js.Value, args []js.Value) interface{} {
if newTodo() != "" {
setTodos(append(todos(), newTodo()))
setNewTodo("")
}
return nil
})
}
return fiber.createElement("div", map[string]interface{}{"class": "container mx-auto p-4"},
fiber.createElement("h1", map[string]interface{}{"class": "text-2xl font-bold mb-4"}, fiber.Text("Todo List")),
fiber.createElement("input", map[string]interface{}{
"type": "text", "value": newTodo(), "onchange": handleInputChange(),
"class": "border rounded px-2 py-1 mr-2",
}),
fiber.createElement("button", map[string]interface{}{
"onclick": handleAddTodo(),
"class": "px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600",
}, fiber.Text("Add Todo")),
fiber.createElement("ul", map[string]interface{}{"class": "mt-4"},
func() []interface{} {
var items []interface{}
for _, todo := range todos() {
items = append(items, fiber.createElement("li", map[string]interface{}{"class": "mb-2"}, fiber.Text(todo)))
}
return items
}()...),
)
}
container := js.Global().Get("document").Call("getElementById", "root")
fiber.render(fiber.createElement(todoList, nil), container)
}
This example demonstrates:
- State management with
useState
- Event handling
- Dynamic rendering of list items
- Use of Tailwind CSS for styling
- Save the code in
main.go
- Build the WebAssembly binary:
GOOS=js GOARCH=wasm go build -o static/bin/main.wasm
- Serve the
static
directory with a web server - Open
index.html
in your browser to see your Todo List in action!
GoWebComponents/
βββ fiber/
β βββ fiber.go # Core framework code
β βββ fiber_examples.go # Example components and applications
βββ static/
β βββ index.html # Entry point for your app
β βββ wasm_exec.js # WebAssembly support
β βββ bin/
β βββ main.wasm # Your compiled WebAssembly binary
βββ scripts/
β βββ build.sh # Build script
β βββ pages.sh # Deployment script for GitHub Pages
βββ go.mod # Go module file
βββ README.md # You are here!
GoWebComponents leverages a virtual DOM approach, similar to React, but implemented entirely in Go. This architecture allows for efficient updates and renders, taking advantage of Go's performance characteristics.
The lifecycle of a GoWebComponents application follows these key stages:
graph TD
A[Start] --> B[Initialize App]
B --> C[Create Root Component]
C --> D[Render Virtual DOM]
D --> E{Is it first render?}
E -- Yes --> F[Create real DOM]
E -- No --> G[Diff with previous Virtual DOM]
G --> H[Update real DOM]
F --> I[Attach Event Listeners]
H --> I
I --> J[Run useEffect Hooks]
J --> K[Wait for State Change]
K --> L{Is there a state change?}
L -- Yes --> M[Update Component State]
M --> D
L -- No --> K
K --> N{Is app closing?}
N -- Yes --> O[Clean up resources]
O --> P[End]
N -- No --> K
-
Initialization:
- The application starts by setting up the WebAssembly environment.
- Go's runtime is initialized in the browser context.
-
Component Creation:
- Components are defined as Go functions that return a virtual DOM structure.
- The
createElement
function is used to build the component tree.
-
Virtual DOM Rendering:
- The virtual DOM is a lightweight Go representation of the actual DOM.
- It's efficiently diffed and patched to minimize actual DOM manipulations.
-
State Management:
- State is managed using the
useState
hook, which returns a getter and setter. - State updates trigger re-renders of the affected components.
- State is managed using the
-
Event Handling:
- Events are bound to Go functions using
js.FuncOf
. - These functions are kept alive to prevent garbage collection.
- Events are bound to Go functions using
-
Effect System:
- The
useEffect
hook allows for side effects and lifecycle management. - Effects are run after the DOM has been updated.
- The
-
WebAssembly Bridge:
syscall/js
is used to interface between Go and JavaScript.- DOM manipulation is done through this bridge, allowing Go code to interact with the browser environment.
-
Reconciliation:
- When state changes occur, the virtual DOM is re-rendered.
- A diffing algorithm determines the minimal set of changes needed to update the real DOM.
-
Memory Management:
- Go's garbage collector handles memory management, including for DOM-related structures.
- Care is taken to properly release JavaScript callbacks to prevent memory leaks.
-
Performance Optimization:
- The use of WebAssembly allows for near-native performance for complex operations.
- The virtual DOM approach minimizes costly DOM manipulations.
This architecture allows GoWebComponents to provide a React-like development experience while leveraging Go's strengths in performance, type safety, and concurrency.
We welcome contributions! Here's how you can help:
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature
- Commit your changes:
git commit -am 'Add amazing feature'
- Push to the branch:
git push origin feature/amazing-feature
- Open a pull request
Join us in shaping the future of web development with Go!
Embrace the power of Go for your entire web stack. With GoWebComponents, you're not just writing code; you're crafting efficient, scalable, and maintainable web applications. Start your journey with GoWebComponents today and experience the future of web development!