feat(config): resolve the API base at runtime from config.js
This commit is contained in:
@@ -11,6 +11,13 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
<!--
|
||||||
|
Runtime config, loaded before the app and deliberately not a module: a
|
||||||
|
classic script blocks until it has run, so window.__UDYAM_CONFIG__ is set
|
||||||
|
before any module code reads it. Served unbundled from the static root so
|
||||||
|
the API base can be changed on the server without rebuilding.
|
||||||
|
-->
|
||||||
|
<script src="/config.js"></script>
|
||||||
<script type="module" src="/src/main.tsx"></script>
|
<script type="module" src="/src/main.tsx"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -19,6 +19,13 @@ server {
|
|||||||
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Runtime config — never cached. It is how the API base is changed without a
|
||||||
|
# rebuild, and a cached copy would silently pin the old URL for every browser
|
||||||
|
# that has already loaded the app, with no way to tell from the server side.
|
||||||
|
location = /config.js {
|
||||||
|
add_header Cache-Control "no-cache, no-store, must-revalidate";
|
||||||
|
}
|
||||||
|
|
||||||
# The API, same-origin. The bundle is built with VITE_UDYAM_API_BASE_URL set
|
# The API, same-origin. The bundle is built with VITE_UDYAM_API_BASE_URL set
|
||||||
# to the relative /api/v1/udyam, so it carries no hostname at all and the
|
# to the relative /api/v1/udyam, so it carries no hostname at all and the
|
||||||
# same dist/ serves from any domain. That also puts the API on the UI's own
|
# same dist/ serves from any domain. That also puts the API on the UI's own
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Runtime configuration — edited on the server, not baked into the bundle.
|
||||||
|
*
|
||||||
|
* Vite inlines import.meta.env.VITE_* at build time, so a bundle built for one
|
||||||
|
* backend URL cannot be pointed at another without rebuilding. That is the wrong
|
||||||
|
* shape for a deployment where the backend goes up first and the UI follows, or
|
||||||
|
* where the same artifact is promoted from demo to staging. This file is served
|
||||||
|
* from the static root unbundled, so ops can change the API base and reload.
|
||||||
|
*
|
||||||
|
* Precedence, highest first:
|
||||||
|
* 1. apiBaseUrl below, if it is a non-empty string
|
||||||
|
* 2. VITE_UDYAM_API_BASE_URL, compiled in at build time
|
||||||
|
* 3. "/api/v1/udyam" — same-origin, which is what the nginx and httpd configs
|
||||||
|
* in DEPLOYMENT.md set up
|
||||||
|
*
|
||||||
|
* Leave it empty for a same-origin deployment; that is the common case and needs
|
||||||
|
* no edit. Set it when the API lives on another host:
|
||||||
|
*
|
||||||
|
* apiBaseUrl: "https://udyamlinc-api.lincpay.tech/api/v1/udyam"
|
||||||
|
*
|
||||||
|
* A cross-origin value also needs that origin in the backend's
|
||||||
|
* UDYAM_CORS_ALLOWED_ORIGINS, or the browser blocks every call while the API
|
||||||
|
* itself looks healthy.
|
||||||
|
*
|
||||||
|
* This file must never be cached — the server configs send no-store for it.
|
||||||
|
* Cached, it silently pins the old URL for anyone who has already loaded the app.
|
||||||
|
*/
|
||||||
|
window.__UDYAM_CONFIG__ = {
|
||||||
|
apiBaseUrl: '',
|
||||||
|
}
|
||||||
+38
-3
@@ -1,8 +1,43 @@
|
|||||||
import axios from 'axios'
|
import axios from 'axios'
|
||||||
|
|
||||||
/** udyamlinc-backend — Spring Boot skeleton, context path /api/v1/udyam. */
|
declare global {
|
||||||
export const API_BASE =
|
interface Window {
|
||||||
import.meta.env.VITE_UDYAM_API_BASE_URL ?? 'http://udyamlinc-backend.lincpay/api/v1/udyam'
|
__UDYAM_CONFIG__?: { apiBaseUrl?: string }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Where the API lives — resolved at runtime, not frozen into the bundle.
|
||||||
|
*
|
||||||
|
* <p>Precedence, highest first:
|
||||||
|
*
|
||||||
|
* 1. `window.__UDYAM_CONFIG__.apiBaseUrl` from `public/config.js`, which is served
|
||||||
|
* unbundled and can be edited on the server. This is what lets the backend be
|
||||||
|
* deployed first and the UI pointed at it afterwards, without a rebuild.
|
||||||
|
* 2. `VITE_UDYAM_API_BASE_URL`, inlined at build time — still useful for `npm run
|
||||||
|
* dev` against a local backend.
|
||||||
|
* 3. `/api/v1/udyam` — relative, so the bundle carries no hostname, works from any
|
||||||
|
* domain, and is same-origin with the API that nginx or httpd proxies. Being
|
||||||
|
* same-origin also means CORS never applies, which removes the largest single
|
||||||
|
* source of works-locally-fails-deployed.
|
||||||
|
*
|
||||||
|
* <p>An empty or whitespace-only value counts as unset. A deployment that writes
|
||||||
|
* `apiBaseUrl: ""` into config.js means "use the default", and treating that as a
|
||||||
|
* real base would send every request to the page's own URL.
|
||||||
|
*/
|
||||||
|
function resolveApiBase(): string {
|
||||||
|
const runtime = window.__UDYAM_CONFIG__?.apiBaseUrl
|
||||||
|
if (typeof runtime === 'string' && runtime.trim() !== '') {
|
||||||
|
return runtime.trim().replace(/\/+$/, '')
|
||||||
|
}
|
||||||
|
const compiled = import.meta.env.VITE_UDYAM_API_BASE_URL
|
||||||
|
if (typeof compiled === 'string' && compiled.trim() !== '') {
|
||||||
|
return compiled.trim().replace(/\/+$/, '')
|
||||||
|
}
|
||||||
|
return '/api/v1/udyam'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const API_BASE = resolveApiBase()
|
||||||
|
|
||||||
/** Short timeout: field devices are on patchy 2G and every screen has a local fallback. */
|
/** Short timeout: field devices are on patchy 2G and every screen has a local fallback. */
|
||||||
export const api = axios.create({ baseURL: API_BASE, timeout: 6_000 })
|
export const api = axios.create({ baseURL: API_BASE, timeout: 6_000 })
|
||||||
|
|||||||
Reference in New Issue
Block a user