CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-astrojs--svelte

Use Svelte components within Astro with server-side rendering and client-side hydration

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

client-hydration.mddocs/

Client Hydration

Client-side hydration system for making server-rendered Svelte components interactive with state management and event handling.

Capabilities

Client Renderer

Main client-side renderer that handles component hydration and mounting.

/**
 * Creates a client-side renderer for a specific DOM element
 * @param element - Target HTML element for component mounting
 * @returns Async function that hydrates or mounts components
 */
declare const clientRenderer: (element: HTMLElement) => (
  Component: any,
  props: Record<string, any>,
  slotted: Record<string, any>,
  options: Record<string, string>
) => Promise<void>;

export default clientRenderer;

The client renderer handles:

  • Component hydration for server-rendered elements
  • Component mounting for client-only elements
  • Prop updates for existing component instances
  • Automatic cleanup on unmount

Component Hydration/Mounting

Hydrates server-rendered components or mounts new components on the client.

/**
 * Hydrates or mounts a Svelte component
 * @param Component - Svelte component constructor
 * @param props - Component properties
 * @param slotted - Slotted content from Astro
 * @param options - Hydration options including client directive
 * @returns Promise that resolves when component is ready
 */
async function hydrateComponent(
  Component: any,
  props: Record<string, any>,
  slotted: Record<string, any>,
  options: { client: string }
): Promise<void>;

Client Directive Handling:

The options.client parameter determines the hydration behavior:

  • "load" - Hydrate immediately
  • "idle" - Hydrate when browser is idle
  • "visible" - Hydrate when component enters viewport
  • "media" - Hydrate based on media query
  • "only" - Mount without hydration (client-only)

Component Instance Management

Creates and manages Svelte component instances with reactive props.

/**
 * Creates a managed Svelte component instance
 * @param Component - Svelte component constructor
 * @param target - Target DOM element
 * @param props - Initial component props
 * @param shouldHydrate - Whether to hydrate or mount fresh
 * @returns Component management interface
 */
function createComponent(
  Component: any,
  target: HTMLElement,
  props: Record<string, any>,
  shouldHydrate: boolean
): ComponentInstance;

interface ComponentInstance {
  setProps(newProps: Record<string, any>): void;
  destroy(): void;
}

State Management:

// Props are managed using Svelte 5's $state rune
let propsState = $state(initialProps);

// Props updates are reactive and trigger re-renders
function setProps(newProps: Record<string, any>) {
  Object.assign(propsState, newProps);
  // Remove props not in newProps
  for (const key in propsState) {
    if (!(key in newProps)) {
      delete propsState[key];
    }
  }
}

Slot Processing

Processes Astro slots for client-side rendering with support for both legacy and modern syntax.

interface SlotData {
  $$slots?: Record<string, any>;
  children?: Snippet;
  [key: string]: Snippet | any;
}

type Snippet = import('svelte').Snippet;

Slot Transformation:

// Legacy slot support
_$$slots = {
  default: true,
  [slotName]: createRawSnippet(() => ({
    render: () => `<astro-slot name="${slotName}">${content}</astro-slot>`
  }))
};

// Modern @render syntax  
renderFns = {
  children: createRawSnippet(() => ({
    render: () => `<astro-slot>${content}</astro-slot>`
  })),
  [slotName]: createRawSnippet(() => ({
    render: () => `<astro-slot name="${slotName}">${content}</astro-slot>`
  }))
};

Instance Tracking

Tracks existing component instances to enable prop updates without remounting.

const existingApplications: WeakMap<HTMLElement, ComponentInstance>;

Instance Lifecycle:

  1. Check if element already has a component instance
  2. If exists, update props via setProps()
  3. If new, create instance via createComponent()
  4. Set up automatic cleanup on astro:unmount event

Usage Examples

Basic Component Hydration:

// Element with server-rendered Svelte component
const element = document.querySelector('[data-svelte-component]');
const renderer = clientRenderer(element);

await renderer(
  MyComponent,
  { title: "Hello", count: 0 },
  { default: "<p>Slot content</p>" },
  { client: "load" }
);

Client-Only Component:

await renderer(
  ClientOnlyComponent,
  { data: apiData },
  {},
  { client: "only" } // Mounts fresh, no hydration
);

Prop Updates:

// Initial render
await renderer(Counter, { count: 0 }, {}, { client: "load" });

// Later update (reuses existing instance)
await renderer(Counter, { count: 5 }, {}, { client: "load" });

Complex Slots:

await renderer(
  LayoutComponent,
  { title: "Page Title" },
  {
    default: "<main>Main content</main>",
    header: "<header>Header</header>",
    sidebar: "<aside>Sidebar</aside>"
  },
  { client: "visible" }
);

Manual Cleanup:

// Components automatically clean up on astro:unmount
element.dispatchEvent(new CustomEvent('astro:unmount'));

docs

client-hydration.md

index.md

integration.md

server-rendering.md

tile.json