ssr

package
v1.16.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 12, 2026 License: MIT Imports: 22 Imported by: 0

Documentation

Overview

Package ssr renders Svelte pages on the server by running the app's server bundle in embedded QuickJS VMs. It is pure Go: no cgo and no Node.

Index

Constants

View Source
const DefaultMaxWorkers = 4

DefaultMaxWorkers caps the default number of VMs. The VMs share the C runtime's allocator, which takes a global lock on every JavaScript function call, so throughput peaks around four concurrent renders and falls with more (see docs/benchmarks.md).

Variables

View Source
var ErrNoEmails = errors.New("ssr: the app has no email templates (src/emails)")

ErrNoEmails is returned when the app has no src/emails.

View Source
var ErrNoEngine = errors.New("ssr: this binary has no JavaScript engine")

ErrNoEngine is what renders that need the JavaScript engine return in a binary built without it, with the tern_nojs tag.

View Source
var ErrTimeout = errors.New("ssr: render timed out")

ErrTimeout is returned when a render exceeds the pool's timeout.

Functions

func WithPayloadValue added in v1.8.0

func WithPayloadValue(ctx context.Context, v any) context.Context

WithPayloadValue gives native rendering the payload as a Go value: whatever encodes to the payload JSON, read into the realm without parsing the JSON. The JavaScript engine uses the JSON.

Types

type Cache added in v1.2.0

type Cache struct {
	// contains filtered or unexported fields
}

Cache remembers renders by payload and URL. A render is a pure function of both: the browser hydrates from the same payload and must produce the same HTML, so a component whose output depends on anything else (the clock, randomness) would not hydrate cleanly either. Pages that look the same for many visitors, such as anonymous pages, then render once.

Concurrent renders of the same page are coalesced into one.

func NewCache added in v1.2.0

func NewCache(next Renderer, maxBytes int) *Cache

NewCache wraps next with a cache of at most maxBytes of HTML.

func (*Cache) Next added in v1.2.0

func (c *Cache) Next() Renderer

Next returns the renderer the cache wraps.

func (*Cache) Render added in v1.2.0

func (c *Cache) Render(ctx context.Context, payload []byte, href string) (Result, error)

Render returns a cached render, or renders and caches it.

func (*Cache) Stats added in v1.2.0

func (c *Cache) Stats() (hits, misses uint64, bytes int)

Stats reports cache hits, misses, and the bytes cached.

type Dev

type Dev struct {
	URL    string // the Vite dev server, e.g. http://127.0.0.1:5174
	Client *http.Client
}

Dev renders through the Vite dev server, so server rendering uses the same up-to-date modules as hot module replacement.

func (*Dev) Email added in v1.2.0

func (d *Dev) Email(ctx context.Context, name string, props []byte) (EmailResult, []byte, error)

Email implements EmailRenderer.

func (*Dev) Render

func (d *Dev) Render(ctx context.Context, payload []byte, href string) (Result, error)

Render implements Renderer.

type EmailRenderer added in v1.2.0

type EmailRenderer interface {
	Email(ctx context.Context, name string, props []byte) (EmailResult, []byte, error)
}

EmailRenderer renders the app's email templates (src/emails). An empty name returns the template names with their preview props, as JSON.

type EmailResult added in v1.2.0

type EmailResult struct {
	Subject string `json:"subject"`
	HTML    string `json:"html"`
	Error   string `json:"error,omitempty"`
}

EmailResult is a rendered email template.

type Native added in v1.5.0

type Native struct {
	// contains filtered or unexported fields
}

Native renders with the app compiled to Go: one realm per worker, so renders run in parallel without the JavaScript engine. A render a realm can't finish (code compiled as unsupported, an exception, a bug in the compiled code) is rendered again by the QuickJS pool, made the first time it's needed.

func (*Native) Close added in v1.5.0

func (n *Native) Close() error

Close waits for renders in progress and releases the realms and the fallback pool.

func (*Native) Email added in v1.13.0

func (n *Native) Email(ctx context.Context, name string, props []byte) (EmailResult, []byte, error)

Email renders an email template natively, or with the JavaScript engine when the realm can't, as Render does for pages.

func (*Native) Render added in v1.5.0

func (n *Native) Render(ctx context.Context, payload []byte, href string) (Result, error)

Render renders payload natively, or with the JavaScript engine when the realm can't.

type NativeOptions added in v1.5.0

type NativeOptions struct {
	// Verify renders every page with the JavaScript engine too and logs
	// where the HTML differs. It returns the engine's result, so it is
	// safe in production while native rendering is checked.
	Verify bool
}

NativeOptions configure a Native renderer beyond the pool's Options.

type NewRealm added in v1.5.0

type NewRealm func(setup func(*js.Realm)) *js.Realm

NewRealm makes a realm with an app's compiled modules evaluated in it, after setup has added host functions. tern build generates one for an app (ADR 0011).

type Options

type Options struct {
	// Workers is the number of VMs, and so the number of concurrent
	// renders. The default is GOMAXPROCS, at most DefaultMaxWorkers.
	Workers int
	// Timeout bounds a single render. The default is 5 seconds.
	Timeout time.Duration
	// MemoryLimit caps each VM's heap, in bytes. The default is 256 MiB.
	MemoryLimit uintptr
	// Logger receives console output from server-side code.
	Logger *slog.Logger
	// Funcs are Go functions the bundle can call while rendering, by name;
	// ctx is the render's context.
	Funcs map[string]func(ctx context.Context, args []any) (any, error)
	// MaxRenders retires a VM after this many renders and replaces it with
	// a fresh one, built in the background. It bounds memory that libraries
	// keep across renders. The default is 10,000; a negative value never
	// retires VMs.
	MaxRenders int
}

Options configure a Pool.

type Pool

type Pool struct {
	// contains filtered or unexported fields
}

Pool renders with a fixed number of reusable VMs. VMs are created on demand; a VM that times out or fails is discarded and replaced.

func NewPool

func NewPool(bundle string, opts Options) (*Pool, error)

NewPool compiles bundle, which must define globalThis.__tern_render, and returns a pool ready to render. It creates one VM up front so a broken bundle fails at startup rather than on the first request.

func (*Pool) Close

func (p *Pool) Close() error

Close releases the pool's VMs. Renders in progress finish first.

func (*Pool) Email added in v1.2.0

func (p *Pool) Email(ctx context.Context, name string, props []byte) (EmailResult, []byte, error)

Email renders an email template with props (JSON).

func (*Pool) Render

func (p *Pool) Render(ctx context.Context, payload []byte, href string) (Result, error)

Render renders payload, waiting for a free VM if all are busy.

type Renderer

type Renderer interface {
	Render(ctx context.Context, payload []byte, href string) (Result, error)
}

Renderer renders a page payload. href is the page's absolute URL.

func NewNative added in v1.5.0

func NewNative(newRealm NewRealm, bundle string, opts Options, nopts NativeOptions) (Renderer, error)

NewNative returns a native renderer. bundle is the server bundle, for the QuickJS fallback. It makes one realm up front: if the compiled modules can't be evaluated, every page renders with the engine.

type Result

type Result struct {
	Head string `json:"head"`
	Body string `json:"body"`
	// Skip reports that the payload is not something the server renders.
	Skip bool `json:"skip"`
}

Result is a rendered page.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL