spa

package
v0.13.0 Latest Latest
Warning

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

Go to latest
Published: Oct 3, 2026 License: Apache-2.0 Imports: 20 Imported by: 0

Documentation

Overview

Package spa serves a single-page app built by Vite from the Go server, in production from the embedded build and in development by proxying to the Vite dev server, so the app has one origin in both.

Index

Constants

View Source
const BuildDir = "_build"

BuildDir is where the app's content-hashed build output goes, set in vite.config.ts as build.assetsDir. Handler caches everything under it as immutable, so it must hold nothing else: files copied from public/ keep their names, and cached forever they could never change.

View Source
const DevNonce = "vite-dev"

DevNonce is the CSP nonce Vite puts on the scripts and styles it injects in development, such as React's refresh preamble, when vite.config.ts sets html.cspNonce to it. A server's development CSP accepts it (see server.New), so its policy can stay strict while it proxies Vite.

Variables

This section is empty.

Functions

func Built added in v0.3.0

func Built(dist fs.FS) bool

Built reports whether dist holds a Vite build rather than the placeholder that lets the Go module build before the web app has: whether Handler serves it or proxies to the dev server. Use it for anything else that differs in development, such as where generated files are read from.

func Handler

func Handler(dist fs.FS, opts Options) (http.Handler, error)

Handler serves the Vite build in dist. For a request path it serves, in order: the file at that path, preferring a precompressed .br or .gz sibling the client accepts; a prerendered <path>/index.html; for a path with no file extension, index.html, so client-side routes work on reload; and otherwise a 404. Files under BuildDir are cached for a year; everything else carries an ETag to revalidate with, and index.html is gzipped for clients that accept it.

When dist holds no build, as when the Go module is built before the web app, Handler proxies every request to opts.DevServer, including Vite's HMR WebSocket. It returns an error if there is neither a build nor a dev server.

func NegotiateLocale added in v0.8.0

func NegotiateLocale(preferred, locales []string, fallback string) string

NegotiateLocale picks the locale for the first preferred tag that has one: an exact match, ignoring case, else a locale with the same base language, so es-MX gets es. It returns fallback when nothing matches. It is the server's half of @parallelworks/i18n's negotiateLocale, and the two agree.

Types

type Locales added in v0.8.0

type Locales struct {
	// Available are the app's locales as the client names them, such as
	// "en" and "es". None leaves index.html as it is.
	Available []string
	// Fallback is chosen when nothing matches. Defaults to Available[0].
	Fallback string
	// Cookie names a cookie holding the person's choice, which wins over
	// Accept-Language.
	Cookie string
}

Locales are the languages an app is translated into, which Handler chooses from for each request and writes to index.html as <html lang>. The client reads it back, as with @parallelworks/i18n's detectLocale(locales, {injected: document.documentElement.lang, ...}), so the first paint is already in the reader's language.

func (Locales) Negotiate added in v0.8.0

func (l Locales) Negotiate(r *http.Request) string

Negotiate returns the locale for r: the Cookie's choice, then the Accept-Language header's languages in order of preference, then Fallback.

func (Locales) NegotiateHeader added in v0.11.0

func (l Locales) NegotiateHeader(h http.Header) string

NegotiateHeader is Negotiate for a request's headers alone, as a problem.Localizer's Locale.

type Options

type Options struct {
	// Index rewrites index.html for a request, for example to add
	// <base href>. It applies in development too, after Locales.
	Index func(r *http.Request, html []byte) []byte
	// Locales sets index.html's <html lang> to the reader's language.
	Locales Locales
	// NotFound reports whether a path other than the root that matches no
	// file and no prerendered page is unknown to the app. Its shell is then
	// sent with a 404, so crawlers see an honest status while the router
	// renders its own page. By default every such path is a client-side
	// route, sent with a 200.
	NotFound func(r *http.Request) bool
	// DevServer is the Vite dev server's URL, such as "http://localhost:5173".
	// When dist holds no build, Handler proxies to it.
	DevServer string
}

Options configure Handler.

Jump to

Keyboard shortcuts

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