core: static sites serve a nested directory's index.html
`try_files {path} {path}/index.html /index.html` for SPA sites and the
dashboard: a URL like /docs/setup/ serves that directory's own index.html
before falling back to the root one, so a multi-page static site works at its
sub-paths while single-page apps still get client-side routing.
Found uncommitted in the checkout, author unknown, and already live: wildpc
runs from this tree, so every Caddyfile generated since used it.
This commit is contained in:
@@ -261,12 +261,15 @@ def _host_remote_block(label: str, host: str, target: str) -> list[str]:
|
|||||||
|
|
||||||
|
|
||||||
def _static_serve_lines(serve_dir: str, spa: bool, indent: str) -> list[str]:
|
def _static_serve_lines(serve_dir: str, spa: bool, indent: str) -> list[str]:
|
||||||
"""The `root`/`file_server` body for a static site. SPA sites get a fallback to
|
"""The `root`/`file_server` body for a static site. SPA sites try a nested
|
||||||
the root `index.html` (client-side routing); content sites (Hugo) get plain
|
directory index (`{path}/index.html`) before falling back to the root
|
||||||
`file_server`, which resolves directory indexes and 404s missing paths."""
|
`index.html` (client-side routing) — so a multi-page static site keeps working
|
||||||
|
at `/sub/dir/` URLs while single-page apps still resolve deep routes. Content
|
||||||
|
sites (Hugo) get plain `file_server`, which resolves directory indexes and
|
||||||
|
404s missing paths."""
|
||||||
lines = [f"{indent}root * {serve_dir}"]
|
lines = [f"{indent}root * {serve_dir}"]
|
||||||
if spa:
|
if spa:
|
||||||
lines.append(indent + "try_files {path} /index.html")
|
lines.append(indent + "try_files {path} {path}/index.html /index.html")
|
||||||
lines.append(f"{indent}file_server")
|
lines.append(f"{indent}file_server")
|
||||||
return lines
|
return lines
|
||||||
|
|
||||||
@@ -456,7 +459,7 @@ def generate_caddyfile_from_registry(
|
|||||||
lines += [
|
lines += [
|
||||||
" handle {",
|
" handle {",
|
||||||
f" root * {root}",
|
f" root * {root}",
|
||||||
" try_files {path} /index.html",
|
" try_files {path} {path}/index.html /index.html",
|
||||||
" file_server",
|
" file_server",
|
||||||
" }",
|
" }",
|
||||||
"}",
|
"}",
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ class TestAcmeMode:
|
|||||||
cf = generate_caddyfile_from_registry(_acme({}))
|
cf = generate_caddyfile_from_registry(_acme({}))
|
||||||
assert "@host_wildpc host wildpc.example.com" in cf
|
assert "@host_wildpc host wildpc.example.com" in cf
|
||||||
assert "root * /data/repos/wildpc/app/dist" in cf
|
assert "root * /data/repos/wildpc/app/dist" in cf
|
||||||
assert "try_files {path} /index.html" in cf
|
assert "try_files {path} {path}/index.html /index.html" in cf
|
||||||
assert "file_server" in cf
|
assert "file_server" in cf
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -213,15 +213,16 @@ The build is run with `VITE_BASE=/`, so a `vite.config` that reads it (see
|
|||||||
@host_my_frontend host my-frontend.example.com
|
@host_my_frontend host my-frontend.example.com
|
||||||
handle @host_my_frontend {
|
handle @host_my_frontend {
|
||||||
root * /data/repos/my-frontend/dist
|
root * /data/repos/my-frontend/dist
|
||||||
try_files {path} /index.html
|
try_files {path} {path}/index.html /index.html
|
||||||
file_server
|
file_server
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
The `try_files {path} /index.html` directive is essential for SPA routing —
|
The `try_files {path} {path}/index.html /index.html` directive handles both SPA
|
||||||
it falls back to `index.html` for any path that doesn't match a static file,
|
routing and multi-page static sites: it serves a matched static file, then a
|
||||||
letting React Router handle client-side routes. The subdomain is the program name,
|
nested directory's own `index.html` (so `/sub/dir/` URLs work), and otherwise
|
||||||
not hand-configured.
|
falls back to the root `index.html` for any unmatched path — letting React Router
|
||||||
|
handle client-side routes. The subdomain is the program name, not hand-configured.
|
||||||
|
|
||||||
## API integration
|
## API integration
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user