refactor(studio): wire vite.config.ts to shared studio API module#115
refactor(studio): wire vite.config.ts to shared studio API module#115miguel-heygen merged 1 commit intomainfrom
Conversation
vanceingalls
left a comment
There was a problem hiding this comment.
Review: refactor(studio): wire vite.config.ts to shared studio API module
What was done well
This is a clean, impactful refactor. The PR replaces ~727 lines of inline route-handler code with a well-structured adapter pattern that delegates to the shared createStudioApi(adapter) module. Key strengths:
-
Excellent separation of concerns. Host-specific logic (Puppeteer browser management, Vite SSR module loading, producer-server proxying) stays in
vite.config.tsvia theStudioApiAdapter, while routing, path validation (isSafePath), file walking, sub-composition HTML building, and MIME detection all live in the shared module where they belong. -
The Hono-to-Connect bridge is clean.
bridgeHonoResponse()correctly streams the response body (critical for SSE progress events) and handles the no-body case. The request-side bridge properly reads the body for non-GET/HEAD methods and forwards headers. -
The
/apiprefix stripping is correct.url.pathname = url.pathname.slice(4)strips/apiso that shared routes like/projects,/projects/:id/preview, etc. match correctly. This was verified against the route definitions. -
Lazy initialization pattern is preserved. Both the bundler (
getBundler) and the Hono app (getApi) are lazily loaded via Vite's SSR module loader, which correctly resolves TypeScript imports for@hyperframes/core/studio-apiand@hyperframes/core/compiler. -
CI is fully green -- typecheck, lint, format, build, and all test suites pass.
Issues
None critical or blocking.
Minor observations / suggestions
-
rendersDirignores its argument. The interface definesrendersDir(project: ResolvedProject): stringbut the adapter implementsrendersDir: () => resolve(dataDir, "../renders"). This works due to TypeScript's structural typing (fewer params assignable to more params), and in this context all projects share the same renders directory, so it is correct behavior. Just noting it as something future readers might find surprising -- a comment like// All projects share a single renders dir in dev modewould help. -
_apilocal type annotation.let _api: { fetch: (req: Request) => Promise<Response> } | null = nullis a structural duck-type forHono. This is a fine choice since it avoids importing Hono directly into the Vite config (Hono is loaded via SSR), but if@hyperframes/core/studio-apiever exported aStudioApitype alias, it would be cleaner to use that. -
Thumbnail caching moved to the shared module. The old code cached thumbnails to disk in the Vite handler; now the shared
thumbnail.tsroute handles the disk cache while the adapter'sgenerateThumbnailjust does the Puppeteer screenshot. This is a good separation. The adapter's in-flight dedup via_thumbnailInflightcorrectly prevents parallel Puppeteer pages for the same frame, and the shared route handles the disk layer. No issue here, just confirming it was reviewed. -
Body reading for POST/PUT. The body is read as a UTF-8 string for all non-GET/HEAD requests. This is fine for the current API surface (JSON bodies and text file content), but would need revisiting if binary uploads (e.g., asset upload) are added in the future.
-
Error handling in bridgeHonoResponse. The
catch {}on reader errors is appropriate for client disconnects, but swallows all errors silently. Consider logging at debug level if you add structured logging later.
Verdict
Approve. This is a well-executed refactor that achieves its stated goal -- both CLI and studio now consume the same shared API module. The adapter cleanly encapsulates Vite-specific concerns, the bridge handles streaming correctly, and no functionality appears to be lost or broken. The observations above are all suggestions for future improvement, not blockers.
vanceingalls
left a comment
There was a problem hiding this comment.
Review: refactor(studio): wire vite.config.ts to shared studio API module
Clean extraction. The Vite config correctly consumes the shared API module via SSR lazy-loading. ~727 lines of inline route handlers replaced with a ~308-line adapter.
What looks good
- Request/response bridging handles both streaming (SSE) and non-streaming responses correctly via
bridgeHonoResponse - Adapter implementation delegates to
createStudioApi(adapter)with proper duck-typing of Hono's.fetch()— no unnecessary indirection - No breaking changes — routes, paths, and behavior are functionally equivalent to the old inline implementation
- CI passes (typecheck, lint, build, all test suites)
Minor suggestions (non-blocking)
rendersDirparameter could be derived fromprojectDirinstead of passed separately- Silent error swallowing in the bridge function could log to debug
- Body-reading assumes text-only — binary payloads would need
.arrayBuffer()
Verdict
Approved. No critical or important issues.
f0692ed to
9c1ebaa
Compare
bdb4434 to
cd8b974
Compare
206f2c6 to
89e22ef
Compare
cd8b974 to
c67943e
Compare
89e22ef to
e051b17
Compare
c67943e to
1a49a4d
Compare
e051b17 to
3f65cce
Compare
1a49a4d to
1e531f2
Compare
3f65cce to
d99cfca
Compare
1e531f2 to
9660e75
Compare
d99cfca to
964ebd7
Compare
8242e33 to
643c61a
Compare
964ebd7 to
4bba2f0
Compare
643c61a to
646266f
Compare
4bba2f0 to
989bd8f
Compare
33105f1 to
22c2c84
Compare
faccb37 to
229f62d
Compare
22c2c84 to
43966ba
Compare
229f62d to
31701fe
Compare
43966ba to
494d4e7
Compare
31701fe to
69a4de3
Compare
494d4e7 to
ef5282c
Compare
69a4de3 to
8a2af77
Compare
ef5282c to
3a49a8e
Compare
8a2af77 to
029329e
Compare
6f7590e to
a46c170
Compare
9356f4e to
37bbab3
Compare
a46c170 to
b3904ee
Compare
37bbab3 to
a57d95f
Compare
b3904ee to
438a377
Compare
99f4d36 to
644ad12
Compare
438a377 to
4a0e7bb
Compare
644ad12 to
bd175b6
Compare
4a0e7bb to
da9e21f
Compare
Replace ~850 lines of inline route handlers with the shared `createStudioApi(adapter)` module from @hyperframes/core/studio-api. The Vite adapter implements StudioApiAdapter with: - Multi-project listing with session resolution - SSR-loaded bundler and linter (via server.ssrLoadModule) - Producer HTTP proxy for rendering - Puppeteer thumbnail generation with inflight dedup - File watcher → HMR bridge Hono fetch is bridged to Vite's Connect middleware with streaming support for SSE endpoints (render progress). Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
da9e21f to
e3e431b
Compare
Merge activity
|

Summary
vite.config.tswith the sharedcreateStudioApi(adapter)moduleStudioApiAdapterfor the Vite dev server context (SSR-loaded bundler/linter, producer HTTP proxy, Puppeteer thumbnails)fetch()to Vite's Connect middleware with streaming support for SSENow both consumers (CLI + studio) use the same shared API module, ensuring feature parity.
Test plan
pnpm --filter @hyperframes/studio devstarts correctly🤖 Generated with Claude Code