fix(studio): inject runtime env overrides for pre-built SPA mode

VITE_STUDIO_* env vars set in the user's shell had no effect when
running `hyperframes preview` because the pre-built studio bundle had
them baked at Vite build time.

The embedded Hono server now collects VITE_STUDIO_* vars from
process.env and injects them as a `window.__HF_STUDIO_ENV__` script
tag into index.html. The client merges this runtime object on top of
the baked `import.meta.env`, so flags like
VITE_STUDIO_ENABLE_BLOCKS_PANEL=1 work as expected at runtime.
This commit is contained in:
Miguel Ángel
2026-05-21 18:27:29 -04:00
parent f51d324ff5
commit 289aa03499
2 changed files with 32 additions and 2 deletions
+22 -1
View File
@@ -481,6 +481,22 @@ export function createStudioServer(options: StudioServerOptions): StudioServer {
app.get("/icons/*", serveStudioStaticFile);
app.get("/favicon.svg", serveStudioStaticFile);
// ── Runtime env injection ───────────────────────────────────────────────
// When the studio is served as a pre-built SPA, Vite `VITE_STUDIO_*` env
// vars were baked at build time. Collect any such vars from the current
// process.env and inject them as `window.__HF_STUDIO_ENV__` so the client
// can pick them up at runtime, overriding the baked defaults.
function buildRuntimeEnvScript(): string {
const overrides: Record<string, string> = {};
for (const [key, value] of Object.entries(process.env)) {
if (key.startsWith("VITE_STUDIO_") && value !== undefined) {
overrides[key] = value;
}
}
if (Object.keys(overrides).length === 0) return "";
return `<script>window.__HF_STUDIO_ENV__=${JSON.stringify(overrides)};</script>`;
}
// SPA fallback
app.get("*", (c) => {
const indexPath = resolve(studioDir, "index.html");
@@ -540,7 +556,12 @@ export function createStudioServer(options: StudioServerOptions): StudioServer {
500,
);
}
return c.html(readFileSync(indexPath, "utf-8"));
let html = readFileSync(indexPath, "utf-8");
const envScript = buildRuntimeEnvScript();
if (envScript) {
html = html.replace("<head>", `<head>${envScript}`);
}
return c.html(html);
});
return { app, watcher };
@@ -30,7 +30,16 @@ export function resolveStudioBooleanEnvFlag(
// and downstream `env[name]` reads would crash. Fall back to `{}` so
// every flag resolves to its declared default outside Vite. Direct
// property access keeps Vite's compile-time transform happy.
const env = (import.meta.env ?? {}) as StudioFeatureFlagEnv;
//
// When the studio is served as a pre-built SPA by the embedded Hono server,
// `import.meta.env` values were baked at build time. The server injects
// `window.__HF_STUDIO_ENV__` with any `VITE_STUDIO_*` env vars from the
// user's shell, so runtime overrides take precedence over baked defaults.
const runtimeEnv =
typeof window !== "undefined"
? ((window as Window & { __HF_STUDIO_ENV__?: StudioFeatureFlagEnv }).__HF_STUDIO_ENV__ ?? {})
: {};
const env = { ...(import.meta.env ?? {}), ...runtimeEnv } as StudioFeatureFlagEnv;
export const STUDIO_PREVIEW_MANUAL_EDITING_ENABLED = resolveStudioBooleanEnvFlag(
env,