Serving from a sub-path
Two variables carry the mount point, one at build time and one at runtime, and they have to agree.
The client's asset URLs are written into index.html at build time; the server learns its mount
point at runtime. A sub-path is therefore two variables, and they have to carry the same value.
VITE_BASE_PATH=/app/ npm run build
BASE_PATH=/app npm startThat serves the app at https://example.com/app/.
What each one does
VITE_BASE_PATH is Vite's base. It rewrites the asset URLs in index.html, and the router reads
it back, so every address the app builds sits below it.
BASE_PATH tells the server which prefix is the app. Anything outside it is a 404. A missing
trailing slash is normalized, so /app and /app/ are the same value to the server, and /app —
the mount point without its slash — is the app's own root.
The Chatfuel proxy routes (/chatfuel/*) stay where they are, above the mount point.
Both or neither. Set one without the other and you have a deployment where the page loads and nothing else does.
When the two disagree
A client built for /app/ and served at the root asks for /app/assets/..., which is not there:
the page arrives, every script 404s, and the app never starts. The other way round is the same
failure from the other side — a client built for the root, served under BASE_PATH=/app, asks for
/assets/..., which is outside the mount point.
You cannot fix either at runtime. The URLs are already in the bundle, so the answer is a rebuild with the value the server is running with.
Not on Vercel
Vercel serves the app from the domain root and supports no sub-path at all. If you need one, run the bundled Node server yourself — on a box you own or in Docker.