Gonertia
repository·3.x·Indexed 42 days ago
https://github.com/romsar/gonertiaA zero-dependency Golang adapter for Inertia.js v3, enabling the creation of single-page applications using server-side routing and controller patterns. It features support for SSR, Vite integration with HMR, asset versioning, and advanced prop patterns including deferred, optional, and merging props.
What's inside Gonertia
- Gonertia is a zero-dependency Inertia.js server-side adapter for Golang. It is designed to allow developers to build single-page applications (SPAs) using server-side patterns, similar to how the official Laravel adapter works. It supports Inertia 3.0 and features like SSR (Server-Side Rendering) and helpers for validation errors.
Use Content Security Policy (CSP) with Vite
3.xTo secure your application with CSP, use the
CSPMiddlewareprovided by the Vite integration. This applies nonces to all generated asset tags.- Wrap your handler:
handler := app.CSPMiddleware()(app.Middleware(mux)). - In your template, use
{{ viteAssetsWithNonce .csp_nonce "path" }}to include the nonce. - Customize the policy using
app.CSPMiddleware(inertia.WithCSPPolicy("..."), inertia.WithCSPNonceGenerator(fn)).
handler := app.CSPMiddleware()(app.Middleware(mux)) // Template usage: // {{ viteAssetsWithNonce .csp_nonce "app.tsx" }}- Wrap your handler:
Integrate with Vite
3.xGonertia provides built-in Vite integration to handle hot module replacement (HMR) and production asset bundling automatically.
Basic Setup
Wrap your Inertia instance with
inertia.NewWithVite(i).Configuration
Use
inertia.NewWithVite(i, ...)with these options:inertia.WithHotFile(path): Path to the Vite hot reload file.inertia.WithBuildManifest(path): Path to the build manifest.inertia.WithFallbackManifest(path): Fallback manifest path.inertia.WithBuildDir(dir): Build output directory.inertia.WithHotReloadPort(port): Hot reload server port.
Template Helpers
{{ .inertiaHead }}: Required in<head>.{{ viteRefresh }}: HMR setup for frameworks like Vue/Preact.{{ vite "path" }}: Resolves asset URLs for dev vs production.{{ viteAssets }}: Outputs all required assets (use withWithEntryPoints).{{ viteAssetsWithNonce .csp_nonce "path" }}: Outputs assets with a CSP nonce.
i, _ := inertia.NewFromFile("resources/views/app.html") app, _ := inertia.NewWithVite(i, inertia.WithBuildManifest("public/build/manifest.json"), inertia.WithHotFile("custom/hot"), ) // In your HTML template: // <script type="module" src="{{ vite "resources/js/app.js" }}"></script>Find community adapters for Gonertia
3.xIf you need an adapter for a specific Go framework not included in the core package, you can check community-maintained options. One available adapter ispetaki/inertia-go. For a complete list of available community adapters, visit the official Inertia.js website.Install Gonertia via go get
3.xTo add Gonertia to your Go project, use the
go getcommand to fetch the v3 package.go get github.com/romsar/gonertia/v3Initialize Gonertia and Render Pages
3.xTo use Gonertia, initialize an
*inertia.Inertiainstance using one of theNewconstructors (from string, file, file system, reader, or bytes). You can then wrap your HTTP handlers withi.Middleware()to integrate with standard Gohttp.Handleror routers like Chi/Gorilla Mux. To render a component, usei.Render(w, r, componentName, props)within your handler.package main import ( "log" "net/http" inertia "github.com/romsar/gonertia/v3" ) func main() { // Initialize from a string or file i, err := inertia.New(rootHTMLString) if err != nil { log.Fatal(err) } mux := http.NewServeMux() // Wrap handler with middleware mux.Handle("/home", i.Middleware(homeHandler(i))) http.ListenAndServe(":8080", mux) } func homeHandler(i *inertia.Inertia) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Render the "Home/Index" component with props err := i.Render(w, r, "Home/Index", inertia.Props{ "some": "data", }) if err != nil { http.Error(w, err.Error(), http.StatusInternalServerError) } }) }How the Inertia Middleware manages request lifecycle
3.xThe
Middlewareworks by wrapping the standardhttp.ResponseWriterwith aninertiaResponseWrapper. This is necessary because the standardhttp.ResponseWriterdoes not allow inspecting the status code or the response body after they have been written.The Lifecycle:
- Intercept: The middleware checks if the request is an Inertia request.
- Wrap: It creates an
inertiaResponseWrapperwhich buffers the response in memory (since Inertia responses are JSON and typically small). - Execute: It calls the next handler in the chain using the wrapper instead of the original writer.
- Post-Process: After the handler finishes, the middleware inspects the wrapper's status code and buffer. It performs automatic redirects (for empty responses or version mismatches) or status code adjustments (302 to 303 for non-GET methods).
- Flush: Finally, it copies the buffered headers, status code, and body from the wrapper back to the original
http.ResponseWriterto complete the HTTP response.
Use Vite template helpers in HTML templates
3.xOnce initialized,
ViteInstanceregisters several helper functions with yourInertiainstance that can be used directly in your Go templates (e.g.,html/template).vite(asset): Resolves an asset path (returns the URL or the path from the manifest).viteReactRefresh(): Returns the<script>tags required for React Fast Refresh (only works in HMR mode).viteRefresh(): Returns the<script>tag for the Vite client (only works in HMR mode).viteAssets: Generates all necessary asset tags.viteAssetsWithNonce(nonce): Generates all asset tags with a provided CSP nonce.
<!-- Example usage in a Go template --> <head> {{ viteReactRefresh }} {{ viteRefresh }} {{ viteAssets }} </head> <!-- Manual asset resolution --> <script src="{{ vite "main.js" }}"></script>Configure Inertia using functional options
3.xThe
gonertiapackage uses the functional options pattern to configure anInertiainstance. You can pass multipleOptionfunctions to the initialization process to customize behavior such as versioning, logging, SSR, and encryption. EachOptionis a function with the signaturefunc(i *Inertia) error.// Example of applying options during initialization // (Assuming an Inertia constructor exists that accepts ...Option) inertia := gonertia.NewInertia( gonertia.WithVersion("1.0.0"), gonertia.WithLogger(myLogger), gonertia.WithSSR("http://localhost:13714"), )Enable Server Side Rendering (SSR)
3.xTo enable SSR, pass the
inertia.WithSSR()option during initialization. By default, it attempts to connect tohttp://127.0.0.1:13714. You can specify a custom URL usinginertia.WithSSR(url).i, err := inertia.New( rootHTMLString, inertia.WithSSR(), // default: http://127.0.0.1:13714 inertia.WithSSR("http://127.0.0.1:1234"), )Custom Prop resolution interfaces
3.xIf you need complex logic to resolve a prop, implement one of the following interfaces. The
Rendermethod will automatically detect and call them:Proper: Returns a value viaProp() any.ProperWithContext: Returns a value viaPropWithContext(ctx context.Context) any.TryProper: Returns a value and an error viaTryProp() (any, error).TryProperWithContext: Returns a value and an error viaTryPropWithContext(ctx context.Context) (any, error).
type UserResolver struct { ID int } func (u UserResolver) PropWithContext(ctx context.Context) any { // Fetch user from DB using context return user } // Usage in Render i.Render(w, r, "User/Profile", Props{"user": UserResolver{ID: 1}})Configure Asset Versioning
3.xTo ensure clients receive updated assets, set an asset version during initialization. You can provide a static string or a path to a manifest file (which Gonertia will use to calculate a checksum).
Options:
inertia.WithVersion(string): Sets a manual version string.inertia.WithVersionFromFile(path): Sets version based on file checksum.inertia.WithVersionFromFileFS(fs, path): Sets version based on file checksum from anfs.FS.
i, err := inertia.New( rootHTMLString, inertia.WithVersion("some-version"), inertia.WithVersionFromFile("./public/build/manifest.json"), inertia.WithVersionFromFileFS(embedFS, "./public/build/manifest.json"), )