go-app Documentation

repository·master·Indexed 27 days ago

https://github.com/maxence-charriere/go-app

A framework for building SEO-friendly, offline-capable Progressive Web Apps (PWA) using Go and WebAssembly (Wasm). It features a declarative, component-based UI syntax, integrated HTTP and component routing, and a diffing algorithm for efficient DOM updates. The toolkit includes utilities for CLI configuration via struct tags and an enriched error handling package.

Tokens
22.2K
Snippets
79
Records
116
Agent score
94%

What's inside go-app

  1. Overview of go-app

    master
    go-app is a Go package designed for building Progressive Web Apps (PWA) using Go and WebAssembly (Wasm). It allows developers to shape UIs using a declarative syntax that creates and composes HTML elements directly within Go code. Applications built with go-app are served using the standard Go HTTP model, making them SEO friendly, installable, and capable of supporting offline mode.
  2. Understand the go-app lifecycle and PWA loading scenarios

    master

    Apps built with go-app are WebAssembly binaries served via HTTP and function as Progressive Web Apps (PWAs) using service workers and caching. There are three primary loading scenarios:

    1. First loading: The initial visit where the page, service worker, and app resources (app.wasm, CSS, JS) are downloaded and cached.
    2. Recurrent loadings: Subsequent visits where the service worker is compared to the cached version. If they are identical, resources are loaded directly from the browser cache.
    3. Loading after an app update: Occurs when the live service worker differs from the cached version. The new page and resources are downloaded and cached.

    Note: Even after an update is downloaded in the background, the user must reload the page to see the modifications, as the current view is still running the cached version.

  3. Manage Static Resources and app.wasm

    master

    Static resources (CSS, JS, images, etc.) and the app.wasm binary are stored in a web directory.

    • app.wasm: Must always be located at /web/app.wasm.
    • Static Resources: Located at /web/RESOURCE_NAME.

    These files can be served by the Go server using the Handler or hosted on remote storage like AWS S3 or Google Cloud Storage.

  4. Create UI components using Declarative Syntax

    master

    Go-app allows you to build reusable, component-based UI elements using pure Go. You define a struct that embeds app.Compo and implement the Render() app.UI method. Inside Render, you compose the UI using functional builders (like app.Div(), app.H1(), app.Text()) and control flow elements like app.If() and app.Else(). Data binding is achieved through methods like .Value() for state and .OnChange() for event handling.

    // A component that displays a Hello world by composing with HTML elements,
    // conditions, and binding.
    type hello struct {
    	app.Compo
    
    	name string
    }
    
    func (h *hello) Render() app.UI {
    	return app.Div().Body(
    		app.H1().Body(
    			app.Text("Hello, "),
    			app.If(h.name != "", func() app.UI {
    				return app.Text(h.name)
    			}).Else(func() app.UI {
    				return app.Text("World!")
    			}),
    		),
    		app.P().Body(
    			app.Input().
    				Type("text").
    				Value(h.name).
    				Placeholder("What is your name?").
    				AutoFocus(true).
    				OnChange(h.ValueTo(&h.name)),
    		),
    	)
    }
  5. Send a push notification from a server

    master

    To trigger a push notification, your server must send a JSON-encoded app.Notification struct to the endpoint provided in the user's subscription.

    Requirement: The notification message must be a JSON-encoded app.Notification object.

    Example fields in the JSON payload:

    • Title: The title of the notification.
    • Body: The main text content.
    • Path: The application path to navigate to when the notification is clicked.
    // Example of creating the JSON payload for a notification
    body, _ := json.Marshal(app.Notification{
    	Title: "Push test from server",
    	Body:  "go-app push notification number",
    	Path: "/mypage",
    })
    
    // This payload is then sent to the push service (e.g., using webpush-go)
    res, err := webpush.SendNotification(body, &sub, &webpush.Options{
    	VAPIDPrivateKey: h.VAPIDPrivateKey,
    	VAPIDPublicKey:  h.VAPIDPublicKey,
    	TTL:             30,
    })
  6. Customize Page Metadata for SEO

    master

    To improve SEO, you should set metadata like the page title and author. This is done within the OnPreRender method using the Page field of the app.Context argument.

    func (h *hello) OnPreRender(ctx app.Context) {
    	ctx.Page.SetTitle("A Hello World written with go-app")
    	ctx.Page.SetAuthor("Maxence")
    }
  7. Test component client lifecycle

    master

    To test client-side behaviors like mounting (OnMount) or navigation (OnNav), use app.NewClientTester(). This emulates the web browser environment.

    Key steps:

    1. Create a tester with app.NewClientTester(compo).
    2. Use disp.Nav(&url.URL{}) to simulate navigation.
    3. Call disp.Consume() to process the resulting UI changes.
    4. Always call defer disp.Close() to release allocated resources.
    type aTitle struct {
    	app.Compo
    	title string
    }
    
    func (t *aTitle) OnMount(ctx app.Context) {
    	t.title = "Testing Mounting"
    }
    
    func (t *aTitle) OnNav(ctx app.Context) {
    	t.title = "Testing Nav"
    }
    
    func (t *aTitle) Render() app.UI {
    	return app.H1().
    		Class("title").
    		Text(t.title)
    }
    
    func TestComponentLifcycle(t *testing.T) {
    	compo := &aTitle{}
    
    	disp := app.NewClientTester(compo)
    	defer disp.Close()
    
    	disp.Nav(&url.URL{})
    	disp.Consume()
    	if compo.title != "Testing Nav" {
    		t.Fatal("bad component title:", compo.title)
    	}
    }
  8. Serve a go-app using the Standard HTTP Server

    master

    Go-app integrates with the Go standard net/http model. To serve an application, you use &app.Handler{} as an http.Handler. You can also define client-side routing using app.Route(path, composerFunc) and then call app.RunWhenOnBrowser() to start the client-side execution. On the server side, use http.ListenAndServe to host the application.

    func main() {
        // Go-app component routing (client-side):
    	app.Route("/", func() app.Composer { return &hello{} })
    	app.Route("/hello", func() app.Composer { return &hello{} })
    	app.RunWhenOnBrowser()
    
        // Standard HTTP routing (server-side):
    	http.Handle("/", &app.Handler{
    		Name:        "Hello",
    		Description: "An Hello World! example",
    	})
    
    	if err := http.ListenAndServe(":8000", nil); err != nil {
    		log.Fatal(err)
    	}
    }
  9. Use the go-app declarative syntax for UI composition

    master

    go-app uses a chaining mechanism based on Go syntax to compose HTML elements and components. You define your UI by implementing the Render() app.UI method on a component struct. Elements are created using functions named after the HTML tag (e.g., app.Div(), app.H1()) and configured via method chaining.

    func (c *myCompo) Render() app.UI {
    	return app.Div().Body(
    		app.H1().
    			Class("title").
    			Text("Build a GUI with Go"),
    		app.P().
    			Class("text").
    			Text("Just because Go and this package are really awesome!"),
    	),
    }
  10. Configure HTML element attributes and styles

    master

    HTML element interfaces provide methods to set attributes and styles using method chaining.

    • Attributes: Use methods like Class(v string), ID(v string), or Type(v string) to set standard attributes. You can chain multiple calls to set multiple attributes.
    • Styles: Use Style(k, v string) to set CSS properties. Multiple styles can be chained.
    • Nesting: Use the Body(children ...UI) method to nest other elements, texts, or components inside standard elements.
    // Setting multiple attributes and styles
    return app.Div().
    	ID("id-name").
    	Class("class-1").
    	Class("class-2").
    	Style("width", "400px").
    	Style("height", "200px").
    	Style("background-color", "deepskyblue")
  11. Migrate from V7 to V8

    master

    Go-app V8 introduces server-side prerendering for SEO, which requires several breaking changes to your codebase. Key migration steps include:

    1. Update Imports: Replace all github.com/maxence-charriere/go-app/v7/pkg/app imports with github.com/maxence-charriere/go-app/v9/pkg/app (or the appropriate V8 version).
    2. Merge Build Directives: V8 no longer requires separate // +build wasm and server-side files. You should merge your client-side main() and server-side main() into a single file. Use app.RunWhenOnBrowser() for the client-side logic and standard http.ListenAndServe for the server-side logic.
    3. Update Routing: Calls to app.Route() and app.RouteWithRegexp() must now be present in the server-side code as well. Note that these functions now register the type of a component rather than an instance; a fresh instance is created upon navigation. Use component lifecycle interfaces (like Mounter) for initialization.
    4. Update Concurrency: Instead of launching raw goroutines from components, use Context.Async() to ensure proper lifecycle management.