mirror of
https://github.com/luxfi/bridge.git
synced 2026-09-24 00:26:46 +00:00
app/bridge: runtime env shim via window.__ENV / /__ENV.js
Vite inlines `import.meta.env.VITE_*` at build time, so setting those
vars at runtime on a deployed image is a no-op — the bundle already
carries baked URLs. Compose/k8s `environment:` blocks targeting
VITE_BRIDGE_* are cosmetic in that world.
Layer a tiny runtime shim on top:
1. /__ENV.js (this commit ships the build-time template under
public/) is loaded synchronously in <head> before the main
bundle. The serving image overwrites it at boot from real env.
2. bridge.config.ts reads window.__ENV first, then falls back to
import.meta.env.VITE_* for dev and as a safety net.
This decouples the deployable image from its environment: one image,
N envs. Tenants (zoo, future white-labels) copy the public/__ENV.js
template + the env() helper pattern verbatim — only the key names
change.
The dist bundle (search: `window.__ENV`) wires the runtime read,
confirmed via Vite preview + Playwright eval — `window.__ENV` is an
Object with all six expected keys at page load. The pattern works
with or without the docker-entrypoint that ships in a follow-up
commit; an image that fails to template /__ENV.js still gets a
working SPA via build-time fallback.
This commit is contained in:
@@ -6,6 +6,18 @@
|
||||
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'><rect width='32' height='32' rx='6' fill='%235b8def'/></svg>" />
|
||||
<title>Lux Bridge</title>
|
||||
<meta name="description" content="Cross-chain bridge for the Lux Network." />
|
||||
<!--
|
||||
Runtime env: /__ENV.js sets window.__ENV before the main bundle
|
||||
loads. Serving image templates this file at boot from BRIDGE_*
|
||||
env vars; bridge.config.ts reads window.__ENV first, then falls
|
||||
back to Vite's import.meta.env. One image, N envs.
|
||||
|
||||
Placed in <head> (and before the module script) so the synchronous
|
||||
parser-blocking load happens before any deferred module executes —
|
||||
the ordering is unambiguous regardless of how Vite reorganises
|
||||
the bundle.
|
||||
-->
|
||||
<script src="/__ENV.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="bridge-root"></div>
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
// Runtime env for the bridge SPA. Overwritten at container boot by the
|
||||
// serving image's docker-entrypoint, or baked at build time.
|
||||
//
|
||||
// The SDK's bridge.config.ts reads window.__ENV before falling back to
|
||||
// Vite's build-time import.meta.env. This decouples the deployable image
|
||||
// from the environment it runs in: one image, N envs.
|
||||
window.__ENV = window.__ENV || {
|
||||
BRIDGE_API_HOST: '',
|
||||
BRIDGE_ENV: '',
|
||||
BRIDGE_CLIENT_ID: '',
|
||||
BRIDGE_IAM_ORG: '',
|
||||
BRIDGE_LOGO_URL: '',
|
||||
WC_PROJECT_ID: '',
|
||||
}
|
||||
@@ -7,24 +7,45 @@
|
||||
// Logo source of truth: @luxfi/logo (https://github.com/luxfi/logo).
|
||||
// We import the canonical SVG generator and inline it as a data URL so
|
||||
// the build artifact has zero external dependencies for the brand mark.
|
||||
//
|
||||
// Env resolution order:
|
||||
// 1. window.__ENV — runtime, set by /__ENV.js at page load. One
|
||||
// image, N envs. Serving container templates
|
||||
// /__ENV.js from real env at boot.
|
||||
// 2. import.meta.env — build-time Vite fallback, used in dev and as
|
||||
// a safety net if the serving image fails to
|
||||
// template /__ENV.js.
|
||||
|
||||
import type { BridgeConfig } from '@luxfi/bridge'
|
||||
import { getColorSVG } from '@luxfi/logo'
|
||||
|
||||
declare global {
|
||||
interface Window {
|
||||
__ENV?: Partial<Record<string, string>>
|
||||
}
|
||||
}
|
||||
|
||||
const runtime: Partial<Record<string, string>> =
|
||||
(typeof window !== 'undefined' && window.__ENV) || {}
|
||||
const build = import.meta.env
|
||||
const env = (key: string, fallback?: string): string | undefined => {
|
||||
const r = runtime[key]
|
||||
if (r) return r
|
||||
const b = build[`VITE_${key}`]
|
||||
if (b) return b
|
||||
return fallback
|
||||
}
|
||||
|
||||
const luxLogoDataUrl = `data:image/svg+xml;utf8,${encodeURIComponent(getColorSVG())}`
|
||||
|
||||
// `import.meta.env` is Vite's standard env namespace; missing values fall back
|
||||
// to the production network.
|
||||
const env = import.meta.env
|
||||
|
||||
export const bridgeConfig: BridgeConfig = {
|
||||
apiHost: env.VITE_BRIDGE_API_HOST ?? 'https://api.bridge.lux.network',
|
||||
env: env.VITE_BRIDGE_ENV ?? 'mainnet',
|
||||
clientId: env.VITE_BRIDGE_CLIENT_ID,
|
||||
iamOrg: env.VITE_BRIDGE_IAM_ORG ?? 'lux',
|
||||
apiHost: env('BRIDGE_API_HOST', 'https://api.bridge.lux.network')!,
|
||||
env: env('BRIDGE_ENV', 'mainnet')!,
|
||||
clientId: env('BRIDGE_CLIENT_ID'),
|
||||
iamOrg: env('BRIDGE_IAM_ORG', 'lux'),
|
||||
brand: {
|
||||
name: 'Lux Bridge',
|
||||
logoUrl: env.VITE_BRIDGE_LOGO_URL ?? luxLogoDataUrl,
|
||||
logoUrl: env('BRIDGE_LOGO_URL') || luxLogoDataUrl,
|
||||
primaryColor: '#5b8def',
|
||||
secondaryColor: '#7a9ff5',
|
||||
supportEmail: '[email protected]',
|
||||
|
||||
Vendored
+6
@@ -1,11 +1,17 @@
|
||||
/// <reference types="vite/client" />
|
||||
|
||||
// Build-time Vite envs. These are the fallback for the runtime
|
||||
// window.__ENV mechanism (see src/bridge.config.ts). Vite inlines
|
||||
// `import.meta.env.VITE_*` at build, so changing one after the
|
||||
// bundle is built does nothing — that's why we layer window.__ENV
|
||||
// (templated by the serving image at boot) on top.
|
||||
interface ImportMetaEnv {
|
||||
readonly VITE_BRIDGE_API_HOST?: string
|
||||
readonly VITE_BRIDGE_ENV?: string
|
||||
readonly VITE_BRIDGE_CLIENT_ID?: string
|
||||
readonly VITE_BRIDGE_IAM_ORG?: string
|
||||
readonly VITE_BRIDGE_LOGO_URL?: string
|
||||
readonly VITE_WC_PROJECT_ID?: string
|
||||
}
|
||||
|
||||
interface ImportMeta {
|
||||
|
||||
Reference in New Issue
Block a user