Skip to content

Dev Mode Rendering

In dev mode (storybook dev), Astro components are rendered on-demand through a request cycle between the browser and the Vite dev server.

  1. Story definition — Stories import Astro components and define variations with different props and slots.

  2. Component detection — The renderer checks imported components for the isAstroComponentFactory flag to identify Astro components.

  3. Server rendering — When an Astro component is detected, a render request is sent to the Vite dev server middleware via HMR (Hot Module Replacement).

  4. Container rendering — The middleware uses Astro’s Container API to render the component with the provided props and slots. The patchCreateAstroCompat wrapper bridges the Astro compiler v2/v3 calling convention difference.

  5. HTML injection — The rendered HTML string is sent back to the client and injected into Storybook’s canvas.

  6. Hydration — Client-side scripts are re-executed to add interactivity. This handles framework islands (e.g. React components inside Astro with client:load) and Alpine.js directives.

  7. Style application — Scoped styles from .astro components are applied. In Astro 6, style sub-module imports (?astro&type=style&index=N&lang.css) are generated by the component marker plugin.

  8. Framework delegation — For non-Astro framework components (React, Solid, Vue, etc.), the renderer delegates directly to the framework-specific renderToCanvas before calling storyFn(). This ordering is critical — it lets reactive frameworks like Solid manage their own rendering lifecycle without orphaned effects.

  9. HMR updates — Changes to components trigger re-renders. The Vite HMR event listeners in render.tsx handle updates while preserving state when possible.

Communication between the browser and server uses Vite’s built-in HMR channel:

  • Client side (render.tsx): Sends astro:render:request events with the component module ID, props, and slots
  • Server side (viteStorybookAstroMiddlewarePlugin.ts): Listens for requests, invokes the Container API, and responds with astro:render:response containing the rendered HTML

This approach avoids additional HTTP endpoints and reuses Vite’s existing WebSocket connection.