Wire demo for production deploy + add server config
Fixes images 404'ing under /arrangement/ — Vite's publicDir copies assets to the build root, but the base prefix is only applied to bundled assets (JS/CSS), not to runtime URL strings. assetUrl() helper resolves paths against import.meta.env.BASE_URL so '/images/foo.png' becomes '/arrangement/images/foo.png' in production while staying '/images/foo.png' in dev. - src/demo/shared/assets.ts — assetUrl() helper - providers.ts + DemoNav.tsx — wrap all public asset paths - nginx/parsons-demos.conf — swag site-conf for parsons.tensordesign.com.au (asset cache regex above SPA fallback regex per nginx first-match rule) - docs/reference/client-demo-deploy.md — server runbook (DNS, swag SUBDOMAINS, mount, htpasswd, deploy loop) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
81
nginx/parsons-demos.conf
Normal file
81
nginx/parsons-demos.conf
Normal file
@@ -0,0 +1,81 @@
|
||||
# Parsons demo host — drop into swag's /config/nginx/site-confs/ directory.
|
||||
#
|
||||
# Serves static demo slices at parsons.tensordesign.com.au/<slice>/ behind
|
||||
# basic auth. One server block, one cert (Let's Encrypt via swag), one
|
||||
# htpasswd covering all slices.
|
||||
#
|
||||
# Document root layout (host filesystem):
|
||||
# <host_path>/parsons-demos/
|
||||
# index.html ← optional landing page listing slices
|
||||
# arrangement/
|
||||
# index.html
|
||||
# assets/...
|
||||
# <other-slices>/
|
||||
#
|
||||
# Bind-mount that directory into swag at /config/www/parsons-demos/ — the
|
||||
# `root` directive below assumes that path. Adjust if you mount elsewhere.
|
||||
|
||||
server {
|
||||
listen 443 ssl;
|
||||
listen [::]:443 ssl;
|
||||
http2 on;
|
||||
|
||||
server_name parsons.*;
|
||||
|
||||
# swag manages the cert chain via SUBDOMAINS — make sure `parsons` is in
|
||||
# the SUBDOMAINS env var of the swag container so this resolves.
|
||||
include /config/nginx/ssl.conf;
|
||||
|
||||
root /config/www/parsons-demos;
|
||||
index index.html;
|
||||
|
||||
# One credential file covering every slice. Create with:
|
||||
# docker exec -it swag htpasswd -c /config/nginx/.htpasswd-parsons client
|
||||
auth_basic "Parsons demos";
|
||||
auth_basic_user_file /config/nginx/.htpasswd-parsons;
|
||||
|
||||
# Optional: don't auth the root listing if you want it publicly visible.
|
||||
# (Currently auth covers it too — change to `auth_basic off;` to expose.)
|
||||
|
||||
# Root path serves the optional landing index.html if present, else 404.
|
||||
location = / {
|
||||
try_files /index.html =404;
|
||||
}
|
||||
|
||||
# Long cache for fingerprinted assets — Vite produces hashed filenames so
|
||||
# this is safe. HTML is short-cache so updates land on next refresh.
|
||||
# NOTE: asset + html regex locations must come BEFORE the slice fallback
|
||||
# below, because nginx uses the first matching regex location.
|
||||
location ~* \.(?:js|css|woff2?|ttf|otf|eot|png|jpg|jpeg|gif|svg|webp|ico)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
access_log off;
|
||||
}
|
||||
|
||||
location ~* \.html$ {
|
||||
expires -1;
|
||||
add_header Cache-Control "no-cache, must-revalidate";
|
||||
}
|
||||
|
||||
# SPA fallback per slice. /<slice>/<react-route> resolves to that
|
||||
# slice's index.html so React Router handles the rest. Static assets
|
||||
# (.js/.css/.png/etc.) are handled by the regex blocks above.
|
||||
location ~ ^/(?<slice>[^/]+)/ {
|
||||
try_files $uri $uri/ /$slice/index.html;
|
||||
}
|
||||
|
||||
# Hide hidden files (e.g. .htpasswd if it ever ends up in webroot)
|
||||
location ~ /\. {
|
||||
deny all;
|
||||
}
|
||||
}
|
||||
|
||||
# HTTP → HTTPS redirect — swag's default server already covers this for
|
||||
# wildcard subdomains, but include explicitly here in case the default is
|
||||
# customised.
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name parsons.*;
|
||||
return 301 https://$host$request_uri;
|
||||
}
|
||||
Reference in New Issue
Block a user