feat(app): support serving the explorer from a configurable base path#617
Open
chai-guy-7 wants to merge 2 commits into
Open
feat(app): support serving the explorer from a configurable base path#617chai-guy-7 wants to merge 2 commits into
chai-guy-7 wants to merge 2 commits into
Conversation
Allow the frontend to be served under a URL subpath (e.g. /explorer)
instead of only at the domain root, for deployments behind
prefix-preserving reverse proxies.
- vite.config.ts: base from VITE_BASE_PATH (build time); Docker builds
use a relative base so one image works at any subpath
- index.html: <base href> tag templated from BASE_PATH (gomplate at
container start or the html-transform plugin locally); config.js and
favicon defaults are now base-relative
- new src/utils/basePath.ts: getBasePath/basePathPrefix/publicAsset/
appUrl/appRootUrl/currentAppPath helpers reading the live <base> tag
- router uses createWebHistory() so vue-router picks up the <base> tag
- absolute /images/... references and window.location redirects
(401 login redirect, wallet switch reload, OAuth redirect_uri and
post_logout_redirect_uri, MetaMask blockExplorerUrls) now resolve
through the helpers; root-deployment output is unchanged
- nginx.conf.subpath.template: serves under ${BASE_PATH} prefix when
the BASE_PATH env var is set; the existing template and rendered
config remain untouched when it is unset
- Dockerfile: VITE_BASE_PATH build arg; CMD normalizes BASE_PATH and
selects the nginx template at container start
Verified at root and under /explorer (direct and behind a
prefix-preserving proxy) against a real nginx with the rendered
configs: assets, deep links, client-side navigation, config.js and
images all resolve; default deployment output is functionally
identical to before.
- prepend the base path to the not-found URL rewrite so the restored address stays inside the app prefix (refresh no longer 404s under a subpath deployment), with regression tests for root and subpath - preserve the query string on the bare-prefix 301 redirect (e.g. /explorer?network=... no longer loses its params) - fail fast at container start when BASE_PATH contains characters outside the documented charset instead of rendering a broken or unsafe nginx config - cross-reference the nginx templates so header/gzip changes do not silently miss subpath deployments, and document the publicAsset convention for contributors
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.
What
Adds support for serving the explorer frontend from a configurable URL base path (e.g.
https://example.com/explorer/) instead of only at the domain root. Motivated by a partner reverse-proxyingx.xx/explorerto their hosted explorer instance, which currently breaks because all assets, the runtimeconfig.js, and several JS redirects assume the app lives at/.How
Two configuration knobs, both backward compatible (defaults reproduce current behavior exactly):
VITE_BASE_PATH=/explorer/ npm run build(also works fornpm run dev). Sets the Vitebaseand keeps the injected<base>tag in sync.docker run -e BASE_PATH=/explorer ...configures everything at container start. This fits the existing pattern whereindex.htmlis templated with gomplate on startup, so the stock published image can serve any subpath.Mechanism:
index.htmlgets a<base href>tag templated fromBASE_PATH(default/). Built asset URLs are emitted relative in Docker builds and resolve against it.config.jsand the favicon defaults are now base-relative.vue-routerusescreateWebHistory()with no argument, which reads the<base>tag, covering both build-time and runtime configuration.src/utils/basePath.tshelpers (getBasePath,basePathPrefix,publicAsset,appUrl,appRootUrl,currentAppPath) with unit tests. All root-absolute/images/...references, the 401 login redirect, the wallet-switch reload, the Prividium OAuthredirect_uri/post_logout_redirect_uri, and MetaMaskblockExplorerUrlsresolve through them. For root deployments every helper returns the exact same strings as before (includinghttps://hostwithout a trailing slash where external allowlists may do exact matching).nginx.conf.subpath.templateused only whenBASE_PATHis set: serves the app under the prefix (with a301from the bare prefix, relative redirects for proxy friendliness, and the same security headers). WhenBASE_PATHis unset, the existing template is used unchanged and the rendered nginx config is byte-identical to today.VITE_BASE_PATHbuild arg, and the CMD normalizesBASE_PATHand picks the right template at startup. Idempotent across container restarts (index.html is always regenerated from the.tpl).release.ymlis intentionally untouched: the published image stays a single artifact, configurable per deployment viaBASE_PATH.Verification
vue-tscclean.BASE_PATH: rendered nginx config identical to current, app loads, deep links work, browser console clean.BASE_PATH=/explorerdirect:/explorer301s to/explorer/,config.js, JS/CSS chunks, images, and deep links (/explorer/tx/0x...) all 200, client-side navigation keeps the prefix, zero failed requests in a headless-browser run.BASE_PATHinput forms (``,/, `/explorer`, `/explorer/`, `explorer`, `explorer/`).window.location.origin, and the nginx prefix rewrite is applied after nginx's standard URI normalization, so no traversal is possible.Note: container-level smoke testing of the actual Docker image (
docker build+docker runwith and withoutBASE_PATH) was not run in this environment (no Docker available); the rendered nginx configs and the startup shell logic were tested directly against a real nginx binary instead. Worth a quick staging check on the built image.Deployment notes
BASE_PATH=/explorerand have their proxy forward/explorer/*to the container without stripping the prefix.BASE_PATHunset (root mode), but the app will emit root-relative URLs, so prefix-preserving proxying is the supported setup.BASE_PATHmust be a plain path prefix (letters, digits,-,_,/), as it is interpolated into an nginxlocation/rewrite.