spa

package
v0.0.0-...-54002ae Latest Latest
Warning

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

Go to latest
Published: Jun 15, 2026 License: Apache-2.0 Imports: 9 Imported by: 0

README

spa

This example serves a single page app directly from an Envoy dynamic module.

The module contains two filters in the same shared library:

  • api-backend handles /api/* requests in Go.
  • spa serves embedded ui/dist assets and falls back to index.html for client-side routes.

No upstream service is needed. Envoy still has a router at the end of the filter chain, but normal responses are generated by the filters before routing.

What it shows

  • multiple filters in one shared library
  • //go:embed static assets
  • local JSON API responses from Go
  • SPA fallback routing
  • immutable cache headers for fingerprinted assets

Embedded assets

spa.go embeds ui/dist. The repository keeps a small tracked fixture there so unit tests and lint work from a clean checkout.

For real frontend changes, replace the fixture by building the UI into ui/dist, then rebuild the shared library.

Run

From the example directory:

make -C examples/spa run

Then open:

http://localhost:10000/

API paths are served by the Go filter:

curl localhost:10000/api/hello
curl localhost:10000/api/time

Test

Unit tests:

make -C examples/spa test

Browser e2e test:

make -C examples/spa e2e

The e2e suite uses Lightpanda and Playwright. See e2e/README.md for browser test details.

Files

  • spa.go contains both filters and the embedded asset handling.
  • cmd/main.go links the ABI layer and imports the example package.
  • ui/dist/ contains the tracked embed fixture.
  • envoy.yaml is a reference bootstrap for local Envoy runs.
  • e2e/ contains the browser based test runner.

Documentation

Overview

Package spa demonstrates serving a Vite + React SPA directly from an Envoy dynamic module — no file system access, no separate web server.

Two filters ship in the same .so:

spa         — serves embedded ui/dist assets; falls back to index.html for
              unmatched paths (SPA client-side routing support)
api-backend — handles /api/* requests directly from Go, no upstream needed

How assets are embedded

The ui/dist directory is embedded at compile time using //go:embed. The Vite build output (index.html + fingerprinted assets/) lives there. For development, run the Vite dev server separately (npm run dev in ui/); for production, run `npm run build` in ui/ then rebuild the .so.

Request routing in Envoy

GET /              → spa filter → index.html (200, text/html)
GET /assets/*.js   → spa filter → fingerprinted asset (200, immutable cache)
GET /api/*         → api-backend filter → JSON (200, application/json)
GET /unknown-page  → spa filter → index.html (SPA client-side routing fallback)

All responses are generated inside the filter — no upstream cluster is contacted. The Envoy router is still required at the end of the chain, but the route can point at a blackhole cluster since it is never reached.

Index

Constants

This section is empty.

Variables

View Source
var UIFS embed.FS

UIFS holds the compiled Vite output, exported so tests can discover fingerprinted asset filenames at runtime.

Functions

func APIHandler

func APIHandler(w *up.Writer, r *up.Request)

APIHandler handles /api/* requests and responds directly from the .so. No upstream cluster is contacted — this IS the backend the SPA calls. Exported for unit testing.

func SPAHandler

func SPAHandler(w *up.Writer, r *up.Request)

SPAHandler serves embedded static assets and falls back to index.html for all other paths, enabling client-side routing (e.g. React Router). Exported for unit testing.

Types

This section is empty.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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