Skip to content

Commit ec45950

Browse files
committed
Prefer Studio dist, rewrite index.html, add vite.svg
Serve pre-built @objectstack/studio dist when available (fast/static); only spawn a Vite dev server as a fallback in dev when dist is missing. Update warnings/log messages accordingly. Add a vite.svg asset to the studio public folder. Change apps/studio vite.config to use a relative base ('./') to support sub-path mounting. In the static plugin, read and rewrite index.html asset paths (href/src starting with '/') to respect the mount path (STUDIO_PATH) and return the rewritten HTML for SPA fallback so the studio works when mounted under a sub-path.
1 parent d9b08eb commit ec45950

4 files changed

Lines changed: 28 additions & 14 deletions

File tree

apps/studio/public/vite.svg

Lines changed: 5 additions & 0 deletions
Loading

apps/studio/vite.config.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const hmrConfig = process.env.VITE_HMR_PORT
99

1010
// https://vitejs.dev/config/
1111
export default defineConfig({
12-
base: process.env.VITE_BASE || '/',
12+
base: process.env.VITE_BASE || './', // Relative base for sub-path mounting (e.g. /_studio/)
1313
resolve: {
1414
dedupe: ['react', 'react-dom'],
1515
alias: {

packages/cli/src/commands/serve.ts

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -229,31 +229,32 @@ export const serveCommand = new Command('serve')
229229
}
230230

231231
// ── Studio UI (--ui) ────────────────────────────────────────────
232+
// Strategy: always prefer pre-built dist/ if it exists (fast, no
233+
// extra process). Only fall back to Vite dev server when dist is
234+
// missing AND we're in dev mode.
232235
let viteProcess: import('child_process').ChildProcess | null = null;
233236

234237
if (options.ui) {
235238
const studioPath = resolveStudioPath();
236239
if (!studioPath) {
237240
console.warn(chalk.yellow(` ⚠ @objectstack/studio not found — skipping UI`));
241+
} else if (hasStudioDist(studioPath)) {
242+
// Serve pre-built static files (works in both dev & production)
243+
const distPath = path.join(studioPath, 'dist');
244+
await kernel.use(createStudioStaticPlugin(distPath));
245+
trackPlugin('StudioUI');
238246
} else if (isDev) {
239-
// Dev mode → spawn Vite dev server & proxy through Hono
247+
// Fallback: dist not built yet → spawn Vite dev server
240248
try {
241249
const result = await spawnViteDevServer(studioPath, { serverPort: port });
242250
viteProcess = result.process;
243251
await kernel.use(createStudioProxyPlugin(result.port));
244252
trackPlugin('StudioUI');
245253
} catch (e: any) {
246-
console.warn(chalk.yellow(` ⚠ Console UI failed to start: ${e.message}`));
254+
console.warn(chalk.yellow(` ⚠ Studio UI failed to start: ${e.message}`));
247255
}
248256
} else {
249-
// Production mode → serve pre-built static files
250-
const distPath = path.join(studioPath, 'dist');
251-
if (hasStudioDist(studioPath)) {
252-
await kernel.use(createStudioStaticPlugin(distPath));
253-
trackPlugin('StudioUI');
254-
} else {
255-
console.warn(chalk.yellow(` ⚠ Studio dist not found — run "pnpm --filter @objectstack/studio build" first`));
256-
}
257+
console.warn(chalk.yellow(` ⚠ Studio dist not found — run "pnpm --filter @objectstack/studio build" first`));
257258
}
258259
}
259260

packages/cli/src/utils/studio.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,15 @@ export function createStudioStaticPlugin(distPath: string) {
262262
return;
263263
}
264264

265+
// Read and rewrite index.html so asset paths respect the mount path.
266+
// The dist may have been built with base '/' (absolute paths like
267+
// /assets/...) which won't resolve when mounted under /_studio/.
268+
const rawHtml = fs.readFileSync(indexPath, 'utf-8');
269+
const rewrittenHtml = rawHtml.replace(
270+
/(\s(?:href|src))="\/(?!\/)/g,
271+
`$1="${STUDIO_PATH}/`,
272+
);
273+
265274
// Redirect bare path
266275
app.get(STUDIO_PATH, (c: any) => c.redirect(`${STUDIO_PATH}/`));
267276

@@ -283,9 +292,8 @@ export function createStudioStaticPlugin(distPath: string) {
283292
});
284293
}
285294

286-
// SPA fallback: serve index.html for non-file routes
287-
const html = fs.readFileSync(indexPath);
288-
return new Response(html, {
295+
// SPA fallback: serve rewritten index.html for non-file routes
296+
return new Response(rewrittenHtml, {
289297
headers: { 'content-type': 'text/html; charset=utf-8' },
290298
});
291299
});

0 commit comments

Comments
 (0)