Skip to content

v0.37.0

Choose a tag to compare

@cuonggt cuonggt released this 02 Oct 04:11
· 15 commits to main since this release

Inertia 3.8: a page's head from Go, and whole numbers past JavaScript's safe range as BigInts. tug spoke Inertia's protocol as v3.0.0 had it, and the client has since added two things the server takes part in. A page's <Head> gave it its title in the browser, once its scripts had run, so without SSR, a search engine's crawler and the app that makes a link's preview, which run no script, saw the root template's title on every page: now a handler gives its page its head from Go, which the client keeps in the document's head, and which a first visit's HTML has too. And a whole number past 2^53 - 1, as a snowflake ID, was rounded on its way to the page: an inertia.BigInt goes as a JavaScript BigInt, which tug gen types bigint.

The post page of examples/inertia:

func (p *posts) show(c *tug.Ctx) error {
	post, err := p.find(c)
	if err != nil {
		return err
	}
	// The post's title and words, in the first visit's HTML too, for a
	// search engine, and a link's preview.
	c.Head(inertia.Title(post.Title), inertia.Meta("description", post.Body))
	return PostsShow.Render(c, PostsShowProps{Post: post})
}

has them in its first visit's HTML, rendered in the browser, with no Node, its title as inertia.Config.Title says it, the root template's own after it:

<title>Hello, tug · tug</title>
<meta data-inertia="description" name="description" content="Pages rendered by React, with props from Go handlers.">
<title>tug</title>

and in its head prop, which the client, with serverHead: true, keeps in the document's head on each visit, its title said by its title callback:

[
  "<title data-inertia=\"title\">Hello, tug</title>",
  "<meta data-inertia=\"description\" name=\"description\" content=\"Pages rendered by React, with props from Go handlers.\">"
]

A page's props with a BigInt:

type Order struct {
	ID    inertia.BigInt `json:"id"`
	Total int64          `json:"total"`
}

go out as the protocol's marker, on a page that says it has one:

{"component":"Orders/Show","props":{"errors":{},"order":{"id":{"$bigint":"900719925474099988"},"total":4200}},"url":"/orders/1","version":"c4b1e0","preserveBigIntegers":true}

and tug gen writes:

export interface Order {
  id: bigint
  total: number
}

What's new:

  • A page's head, from Go: c.Head(...) gives the page a request renders the elements of its <head>: inertia.Title; inertia.Meta, by name, as the description; inertia.Property, Open Graph's, as og:image; and inertia.Link, as the canonical one. Each is written from its parts, each value escaped, and no HTML is taken from the app, as the client puts them in the page as HTML. inertia.WithHead is the same for middleware, as one that gives every page the site's image, and for any router.
  • Keyed: each element carries data-inertia, its key: title, the meta tag's name or property, the link's rel. The client matches elements by it from page to page, and a page's <Head> element with that head-key wins over the server's. A later element of a key replaces the earlier, the handler's middleware's, and Key gives one a key of its own, as a second og:image needs.
  • In the client's head: the elements go out as the page's head prop, which Inertia's client, from 3.5.0, keeps in the document's head with its serverHead option, as a visit goes to another page, and back. A partial reload leaves it out unless it asks for it. It isn't a shared prop, which an instant visit takes on to the next page, and a page's own head prop wins. An error page has middleware's head, not the one its handler gave the page it meant to render.
  • In the first visit's HTML: {{ .InertiaHead }} has the head of a page rendered in the browser, its title as inertia.Config.Title says it, as the client's title callback does, so a search engine and a link's preview see each page's own, with no Node. The title has no key: React's and Vue's adapters replace it with their own, the same, and Svelte puts the document's title in it. A page rendered on the server has the head from its client's code, with serverHead, and tug adds none.
  • Big integers: inertia.BigInt, an int64, goes out as the protocol's {"$bigint": "..."}, a small one too, in props of any type and in flash data, and its page says preserveBigIntegers, for Inertia's client, from 3.8.0, to make each a BigInt. tug gen types it bigint, in props, flash data and a route's input. A page without one goes as it did, and an int64 is a number, as before.
  • Read back: the client sends a BigInt back as its digits, which Bind reads into an inertia.BigInt from JSON, a form, the query or the path, as it reads an int64, with "must be a whole number" for one that isn't. tugtest's Props, Prop and Flash read one from a page as the number it is, into an inertia.BigInt, an int64 or a json.Number.
  • The starters, on Inertia 3.8: ^3.8.0, serverHead on, {{ .InertiaHead }} in every root template, not only an SSR one's, its own <title> without a key, pageTitle for inertia.Config.Title, and the home page's title and description from its handler. Svelte's serverHead is a function that leaves the title out, as Svelte puts the document's title in the first <title>, which its adapter's head would take away as a visit leaves the page: a Svelte page, the home page too, has its title from Head.svelte. examples/inertia's post page has its title and words from its handler.
  • The guide: Pages, a section on a page's head, and one on numbers past JavaScript's safe range; TypeScript, bigint; Testing, a BigInt read back; SSR and Accounts, the head; and the README.

Upgrading: nothing an app calls changed: go get github.com/cuonggt/tug@v0.37.0, and an app that gives no head from Go and has no inertia.BigInt goes as it did, with the same types, and its tests pass as they did. To give its pages a head from Go, an app made before puts {{ .InertiaHead }} in app.html, before its <title>, as an app made with -ssr has it, and takes that <title>'s data-inertia off, which Svelte needs; turns on serverHead: true in createInertiaApp, on Inertia 3.5.0 or later, or in Svelte, a function that leaves the title out, as a new app's resources/js/inertia.ts has it; and gives inertia.Config a Title that says a title as its title callback does. An inertia.BigInt needs Inertia 3.8.0, as a new app's package.json has it.

The guide is in docs/. tug needs Go 1.26.