Limitations
No server-side rendering of component internals
Section titled “No server-side rendering of component internals”A component’s shadow content is produced by setup() when the element
connects, in the browser. alacris has no server renderer, and alacris-go does
not add one.
What the server renders is the element, its attributes, and its light-DOM slot children. Between first paint and the module loading, the element is present and empty.
Consequences:
- Content that must be in the initial HTML (for SEO, for readers with JavaScript disabled, for an email client) has to be slot content, not component internals.
- There is a flash unless you use
alacris.Pending, and a reflow regardless unless you reserve space in your own CSS.
No declarative shadow DOM
Section titled “No declarative shadow DOM”define() always calls attachShadow and renders into it. Serving
<template shadowrootmode> would leave the declarative content in place and
add the rendered content, so it is not supported.
Props must match their declared type
Section titled “Props must match their declared type”alacris coerces an attribute using the type of the prop’s default. A Go value of a different shape does not error. It produces something the component did not expect:
define('x-y', { props: { tags: [] } }); // object default: JSON.parsealacris.E("x-y").Prop("tags", "a,b") // not JSON; the component silently keeps []JSON.parse failing falls back to the default silently, on the client,
where you will not see it. Generated wrappers make this impossible; hand-written
Prop calls do not.
Numbers are JavaScript numbers
Section titled “Numbers are JavaScript numbers”Integers past 253−1 cannot cross. The library refuses rather than rounding, but the constraint is real: use strings for large identifiers, and have the component treat them as strings.
Decimal currency has the usual float problem. Send minor units as an integer, or
a string, or a struct, not a float64.
The live layer needs a stateful server
Section titled “The live layer needs a stateful server”Sessions live in the memory of the process that created them:
- Session affinity is required behind a load balancer.
Broadcastreaches one instance’s sessions. Fanning out across instances needs your own bus. See Deploying.- SSE is a held connection. Proxies must not buffer it, and your
http.Servermust not have aWriteTimeout.
Layers one and two have none of these properties.
Patches address elements by id
Section titled “Patches address elements by id”An element the server intends to patch needs an id, and it has to be unique on
the page. There is no selector support: a selector that matches
two elements, or none, fails in a way the server cannot see.
No built-in optimistic updates
Section titled “No built-in optimistic updates”An action is a round trip. The page shows the change when the server says so. For a slow network that is visible, and the library does not hide it.
You can do it by hand: have the component update locally and emit, and let the server’s patch confirm or correct it. Nothing coordinates that for you, and reconciling a rejected optimistic update is your problem.
No file uploads through actions
Section titled “No file uploads through actions”An action is JSON, size-capped. Upload with an ordinary form or fetch, then
send an action referring to the result.
What is not supported in alacris templates
Section titled “What is not supported in alacris templates”These come from the runtime, and matter when writing the JavaScript half:
- Dynamic tag names:
html`<${tag}>`does not work. - Bindings inside
<textarea>or<title>text: use.value/.textContent. - Unquoted partial attributes: write
class="a ${b}", notclass=a${b}.
Browser support
Section titled “Browser support”Needs <template>, TreeWalker, and (for component styles)
adoptedStyleSheets: Chrome/Edge 73+, Safari 16.4+, Firefox 101+. There is a
<style> fallback where constructable stylesheets are missing.
The live client needs EventSource and fetch, which is a wider set than the
above.
Desktop host
Section titled “Desktop host”The app module opens the OS webview onto loopback HTTP. That needs CGO and
the platform webview: Xcode Command Line Tools on macOS, WebView2 on Windows,
libwebkit2gtk on Linux. Cross-compiling CGO is not supported.
The host binds 127.0.0.1, checks Host, and (on Run) requires a host
token the webview alone holds. EventSource still needs HTTP, so there is no
custom scheme. See Desktop apps.
Native menus and trays are installed on macOS, Windows, and Linux. Dialogs
(SaveFile, Message, …) work on all three (zenity or kdialog on Linux).
When to use something else
Section titled “When to use something else”| If you need | Consider |
|---|---|
| Component internals in the initial HTML | A server-rendered template language, or a framework with real SSR |
| To swap server-rendered HTML | htmx, Datastar, Turbo |
| A large client-side app with routing and its own state | A client framework |
| Interactive islands with SSR and hydration | Astro with a UI framework |
| Native widgets, not web components | Fyne |
| JS bindings to Go methods inside a webview | Wails |
alacris-go is at its best when the server owns the data, the browser owns the interaction, and you would rather write Go than a client-side state layer.