Gonertia is a well-tested and zero-dependency Inertia.js server-side adapter for Golang. Visit inertiajs.com to learn more.
Inertia allows you to create fully client-side rendered, single-page apps, without the complexity that comes with modern SPAs. It does this by leveraging existing server-side patterns that you already love.
This package based on the official Laravel adapter for Inertia.js: inertiajs/inertia-laravel.
- Tests
- Helpers for testing
- Helpers for validation errors
- Examples
- SSR
Install using go get
command:
go get github.com/romsar/gonertia
Initialize Gonertia in your main.go
:
package main
import (
"log"
"net/http"
inertia "github.com/romsar/gonertia"
)
func main() {
i, err := inertia.New(rootHTMLString)
// i, err := inertia.NewFromFile("resources/views/root.html")
// i, err := inertia.NewFromReader(rootHTMLReader)
// i, err := inertia.NewFromBytes(rootHTMLBytes)
if err != nil {
log.Fatal(err)
}
// Now create your HTTP server.
// Gonertia works well with standard http server library,
// but you are free to use some external routers like Gorilla Mux or Chi.
mux := http.NewServeMux()
mux.Handle("/home", i.Middleware(homeHandler(i)))
}
func homeHandler(i *inertia.Inertia) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
err := i.Render(w, r, "Home/Index", inertia.Props{
"some": "data",
})
if err != nil {
handleServerErr(w, err)
return
}
}
return http.HandlerFunc(fn)
}
Create root.html
template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- Put here your styles, meta and other stuff -->
{{ .inertiaHead }}
</head>
<body>
{{ .inertia }}
<script type="module" src="/build/assets/app.js"></script>
</body>
</html>
Set asset version (learn more)
i, err := inertia.New(
/* ... */
inertia.WithVersion("some-version"), // by any string
inertia.WithVersionFromFile("./public/build/manifest.json"), // by file checksum
)
SSR (Server Side Rendering) (learn more)
To enable server side rendering you have to provide an option in place where you initialize Gonertia:
i, err := inertia.New(
/* ... */
inertia.WithSSR(), // default is http://127.0.0.1:13714
inertia.WithSSR("http://127.0.0.1:1234"), // custom url http://127.0.0.1:1234
)
Also, you have to use asset bundling tools like Vite or Webpack (especially with Laravel Mix). The setup will vary depending on this choice, you can read more about it in official docs or check an example that works on Vite.
Closure and lazy props (learn more)
props := inertia.Props{
"regular": "prop",
"closure": func () (any) { return "prop" },
"closure_with_err": func () (any, error) { return "prop", nil },
"lazy": inertia.LazyProp(func () (any, error) {
return "prop", nil
},
}
i.Render(w, r, "Some/Page", props)
Also, Gonertia have support for always
props (learn more):
props := inertia.Props{
"foo": inertia.AlwaysProp{"bar"},
}
Redirects (learn more)
func homeHandler(i *inertia.Inertia) http.Handler {
fn := func(w http.ResponseWriter, r *http.Request) {
i.Location(w, r, "/some-url")
}
return http.HandlerFunc(fn)
}
NOTES: If response is empty - user will be redirected to the previous url, just like in Laravel official adapter.
To manually redirect back, you can use Back
helper:
i.Back(w, r)
Share template data (learn more)
i.ShareTemplateData("title", "Home page")
<h1>{{ .title }}</h1>
i.ShareTemplateFunc("trim", strings.TrimSpace)
<h1>{{ trim " foo bar " }}</h1>
ctx := inertia.WithTemplateData(r.Context(), "title", "Home page")
// pass it to the next middleware or inertia.Render function using r.WithContext(ctx).
Share prop globally (learn more)
i.ShareProp("name", "Roman")
ctx := inertia.WithProp(r.Context(), "name", "Roman")
// or inertia.WithProps(r.Context(), inertia.Props{"name": "Roman"})
// pass it to the next middleware or inertia.Render function using r.WithContext(ctx).
Validation errors (learn more)
ctx := inertia.WithValidationError(r.Context(), "some_field", "some error")
// or inertia.WithValidationErrors(r.Context(), inertia.ValidationErrors{"some_field": "some error"})
// pass it to the next middleware or inertia.Render function using r.WithContext(ctx).
- Implement JSONMarshaller interface:
import jsoniter "github.com/json-iterator/go"
type jsonIteratorMarshaller struct{}
func (j jsonIteratorMarshaller) Decode(r io.Reader, v interface{}) error {
return jsoniter.NewDecoder(r).Decode(v)
}
func (j jsonIteratorMarshaller) Marshal(v interface{}) ([]byte, error) {
return jsoniter.Marshal(v)
}
- Provide your implementation in constructor:
i, err := inertia.New(
/* ... */,
inertia.WithJSONMarshaller(jsonIteratorMarshaller{}),
)
i, err := inertia.New(
/* ... */
inertia.WithLogger(), // default logger
inertia.WithLogger(somelogger.New()), // custom logger
)
i, err := inertia.New(
/* ... */
inertia.WithContainerID("inertia"),
)
Of course, this package provides convenient interfaces for testing!
func TestHomepage(t *testing.T) {
body := ... // get an HTML or JSON using httptest package or real HTTP request.
// ...
assertable := inertia.Assert(t, body) // from io.Reader body
// OR
assertable := inertia.AssertFromBytes(t, body) // from []byte body
// OR
assertable := inertia.AssertFromString(t, body) // from string body
// now you can do assertions using assertable.Assert[...] methods:
assertable.AssertComponent("Foo/Bar")
assertable.AssertVersion("foo bar")
assertable.AssertURL("https://example.com")
assertable.AssertProps(inertia.Props{"foo": "bar"})
// or work with the data yourself:
assertable.Component // Foo/Bar
assertable.Version // foo bar
assertable.URL // https://example.com
assertable.Props // inertia.Props{"foo": "bar"}
assertable.Body // full response body
}
Also, you can check one more golang adapter called petaki/inertia-go.
Full list of community adapters is located on inertiajs.com.
This package is based on inertiajs/inertia-laravel and uses some ideas of petaki/inertia-go.
Gonertia is released under the MIT License.