Skip to content

feat: let the client be served from a sub-path - #16

Closed
RohanReddy44 wants to merge 1 commit into
mainfrom
feat/base-path
Closed

RohanReddy44 wants to merge 1 commit into
mainfrom
feat/base-path

Conversation

@RohanReddy44

Copy link
Copy Markdown
Collaborator

The client assumed it owned the origin root. Behind a shared domain at /experience, assets, fonts, config.json and the API were all absolute from / and every one of them 404'd.

Subdomains avoid all of this, but a box running several apps behind one proxy cannot always have them, and a reference client should not require one.

How it works

One image, any mount path, no rebuild:

environment:
  BASE_PATH: /experience
location /experience/ {
    proxy_pass http://experience-ui:8080/;   # trailing slash strips the prefix
}

Assets are relative (vite base: "./"), and the container rewrites the <base href> in index.html at start-up using the base image's envsubst template hook plus sub_filter. CONFIG_URL and the API paths resolve against document.baseURI for the same reason. BASE_PATH unset leaves everything at the root exactly as before.

nginx.conf becomes nginx.conf.template so the entrypoint can substitute the variable. I checked that envsubst does not eat nginx's own $uri and $cache_control — it only substitutes variables that exist in the environment.

Two things this turned up

Each would have looked like a different bug:

The router matched against the origin root, so under a prefix the page loaded, the config resolved, React mounted — and then every route 404'd. It now takes its basepath from the same <base href>.

Six icon paths were absolute strings in the header and recording controls, so only those images broke while everything else worked.

Verified both ways

Against the built image with a second nginx container acting as the edge proxy — at /experience/ and at /, with BASE_PATH set and unset:

/experience/ /
page, /chat route 200, renders 200, renders
config.json 200 200
brand/logo.png 200 200
assets/settings.svg 200 200
fonts/poppins-400.ttf 200 200

Screenshotted at the sub-path to confirm the icons and fonts actually render, not just return 200.

Worth knowing operationally

nginx resolves a proxy_pass hostname once at config load. Restart the app container and the proxy keeps the old address until it is reloaded — I hit a 502 from exactly this while testing, and it looks like the app is down when it is not.

Not included

docker-compose.deploy.yml is left untracked, as you asked. The BASE_PATH knob is documented in the README and wired into the repo's own docker-compose.yml.

🤖 Generated with Claude Code

It assumed it owned the origin root. Assets, fonts, config.json and the
API were all absolute from /, so behind a shared domain at /experience
every one of them 404d — and the config failure was silent, because an
unreachable config.json falls back to the bundled defaults.

Subdomains would avoid all of this, but a deployment with several apps
behind one proxy cannot always have them, and a reference client should
not require one.

Assets are relative now (vite base: "./"), and the container rewrites
<base href> from BASE_PATH at start-up, using the base image's envsubst
template hook and sub_filter. One image serves from / or from
/experience/ with no rebuild. CONFIG_URL and the API paths resolve
against document.baseURI for the same reason.

Two things this turned up that would each have looked like a different
bug:

- the router matched against the origin root, so every route 404d under a
  prefix while the page itself loaded. It now takes its basepath from the
  same <base href>
- six icon paths in the header and recording controls were absolute
  strings, so only those images broke

Verified both ways against the built image behind a second nginx acting
as the edge proxy: at /experience/ and at /, every asset, font,
config.json and the rendered page.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@RohanReddy44

Copy link
Copy Markdown
Collaborator Author

Superseded by the simpler build-time approach — see the replacement PR. This one resolved the base path at container start so one image could serve any path; that costs a fragile sub_filter string match and a less common pattern, and the path is known at build time anyway.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant