Served the frontend's build output from server.frontend.dir

internal/frontend serves a Vite build from an fs.FS: hashed files under
/assets/ are cached for a year, HTML and other files get no-cache, ETags are
computed (and cached for a build that can't change), precompressed variants
are served when the client accepts them, and a path without an extension
falls back to index.html for client-side routes. Only GET and HEAD are
allowed.

server.WithFrontend serves it for every path outside /api and /ws, behind
compression and the frontend group's hooks. job-search serve passes the
directory in server.frontend.dir, checked for an index.html at start; empty
means no frontend. Its option building moved into serverOptions, with the
access log.
This commit is contained in:
bwilliams committed 2026-10-16 16:00:34 +01:00
1 parent 155b84caea
commit 9905ffb4cb
7 files changed
+430 -36

No files matched your search

+4 -6
View File
@@ -90,7 +90,7 @@ The `server` section is split into a number of sub-sections:
| `server.csrf` | CSRF and cross-origin protection settings |
| `server.tls` | TLS certificate, minimum version and HTTP redirect |
| `server.headers` | HTTP header settings including policy headers |
| `server.frontend` | How the frontend is served (not used yet) |
| `server.frontend` | Where the frontend's build output is and how it is cached |
| `server.websocket` | Websocket configuration |
#### Server
@@ -177,13 +177,11 @@ The `server` section is split into a number of sub-sections:
#### Frontend
Not used yet.
| Key | Type | Default | Notes |
|---|---|---|---|
| `server.frontend.dir` | string | | Serve the frontend from this directory; empty: the embedded build |
| `server.frontend.immutable_prefix` | string | | Where Vite emits content-hashed files |
| `server.frontend.index_cache_control` | string | | `Cache-Control` of HTML and other files without a hash; empty: none |
| `server.frontend.dir` | string | | Directory of the frontend's build output, holding `index.html`; empty: no frontend is served (there is no embedded build yet) |
| `server.frontend.immutable_prefix` | string | | Where Vite emits content-hashed files, cached for a year; empty: `/assets/` |
| `server.frontend.index_cache_control` | string | | `Cache-Control` of HTML and other files without a hash; empty: `no-cache` |
#### Websockets
+6 -5
View File
@@ -7,11 +7,12 @@ import (
// JSCKServerFrontend is the frontend section's configuration key.
const JSCKServerFrontend string = "frontend"
// JSCServerFrontend configures how the server serves the frontend. Nothing
// reads it yet. Dir serves the frontend from disk instead of the embedded
// build; empty means the embedded build. ImmutablePrefix is where Vite emits
// content-hashed files, and IndexCacheControl the Cache-Control of HTML and
// other files without a hash; empty means none.
// JSCServerFrontend configures how the server serves the frontend. Dir is
// the directory of the frontend's build output (holding index.html); empty
// means no frontend is served, as there is no embedded build yet.
// ImmutablePrefix is where Vite emits content-hashed files, cached for a
// year; empty means "/assets/". IndexCacheControl is the Cache-Control of
// HTML and other files without a hash; empty means "no-cache".
type JSCServerFrontend struct {
Dir string `cfg:"dir"`
ImmutablePrefix string `cfg:"immutable_prefix"`