Repository navigation
feat: let the client be built for a sub-path - #17
Merged
Merged
Conversation
It assumed it owned the origin root. Behind a shared domain at /experience, assets, fonts, config.json and the API were all absolute from /, so every one of them 404d — and the config failure was silent, because an unreachable config.json falls back to the bundled defaults. VITE_BASE_PATH is a Docker build arg, baked into the bundle. Default "/" is the origin root and nothing changes. An image built with a sub-path serves only from that path, so a deployment needing two paths builds two images; the path is known at build time, so that is an acceptable trade for the smaller mechanism. Vite rewrites what it can see — index.html, imported assets, CSS urls. Three things it cannot see needed the prefix by hand: - the API base and config.json URL - six icon paths in the header and recording controls, which are string literals pointing at public/ - the brand asset paths from config.json, which are data. A CDN URL is left alone; a path is resolved against the base The router needed it too. Without a basepath it matches against the origin root, so under a prefix the page loads, the config resolves and React mounts — and then every route 404s, which looks like a different bug entirely. Verified with a second nginx container as the edge proxy: built for /experience/ and served through it, and the default build served at the root, checking the page, the /chat route, config.json, the logo, the icons and the fonts in both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Covers the build arg, the two nginx blocks it needs, and the constraint that an image built for a sub-path serves only from that path. Also notes the trap that cost time while testing: nginx resolves a proxy_pass hostname once at config load, so restarting the app container gives a 502 that looks like the app being down until the proxy is reloaded. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The previous commit resolved brand asset paths through a helper that stripped leading slashes and skipped anything that looked like a URL. The browser already does this: a relative URL resolves against the page, an absolute one is left alone. The helper was guarding against nothing, and I had it duplicated in two files. Config values are now read straight through. The contract is stated in the README instead: a file under public/ is referenced without a leading slash, and anything else is a full URL. import.meta.env.BASE_URL stays where the path is code rather than config — the API base, the config.json URL, the router basepath and the six public/ icon paths. That is Vite's own idiom for exactly this. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Replaces #16, which did the same thing at container start. The path is known at build time, so this is the smaller mechanism and the conventional one.
The client assumed it owned the origin root. Behind a shared domain at
/experience, assets, fonts,config.jsonand the API were all absolute from/and every one of them 404'd — and the config failure was silent, because an unreachableconfig.jsonfalls back to the bundled defaults.How it works
docker build --build-arg VITE_BASE_PATH=/experience/ -t experience-ui .Default is
/and nothing changes. In CI it comes from aVITE_BASE_PATHrepository variable.The trade: the path is baked into the bundle, so an image built for a sub-path serves only from that path. A deployment needing two paths builds two images. That is the cost of the simpler mechanism, and it is fine while the path is known when the image is built.
What Vite does not handle
It rewrites
index.html, imported assets and CSSurl(). Three things were invisible to it:config.jsonURL — nowimport.meta.env.BASE_URL-prefixedpublic/, so only those images broke while everything else workedconfig.json— these are data, not code. A CDN URL is left alone; a path is resolved against the baseThe one that looked like a different bug
The router matched against the origin root. Under a prefix the page loaded, the config resolved, React mounted — and then every route 404'd. It now takes
basepathfromimport.meta.env.BASE_URL. Worth knowing because "the assets load" is not evidence that it works.Verified
A second nginx container as the edge proxy, both ways:
/experience///chatrouteconfig.jsonbrand/logo.pngassets/settings.svgfonts/poppins-400.ttfScreenshotted at the sub-path, since status codes would not have caught either of the two real bugs.
Operationally
nginx resolves a
proxy_passhostname once at config load. Restart the app container and the proxy keeps the old address — I hit a 502 from exactly this while testing, and it looks like the app is down when it is not. Reload the edge after redeploying.🤖 Generated with Claude Code