or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

component-system.mdcustom-elements.mddevelopment-tools.mdindex.mdjsx-support.mdreactivity.mdrendering.mdsfc-compilation.mdssr.mdutilities.md
tile.json

ssr.mddocs/

Server-Side Rendering

Vue's SSR capabilities provide complete server-side rendering support with streaming, hydration, context management, and multiple output formats for building universal applications.

Capabilities

Render Functions

String Rendering

/**
 * Render Vue application to HTML string
 * @param app - Vue application instance
 * @param context - SSR context object
 * @returns Promise resolving to HTML string
 */
function renderToString(
  app: App,
  context?: SSRContext
): Promise<string>;

Usage Example:

import { createSSRApp } from "vue";
import { renderToString } from "vue/server-renderer";

const app = createSSRApp({
  template: `<div>{{ message }}</div>`,
  data: () => ({ message: 'Hello SSR!' })
});

const html = await renderToString(app);
console.log(html); // <div>Hello SSR!</div>

Stream Rendering

/**
 * Render to a simple readable stream
 * @param app - Vue application instance
 * @param context - SSR context object
 * @returns Simple readable stream
 */
function renderToSimpleStream(
  app: App,
  context?: SSRContext
): SimpleReadableStream;

/**
 * Render to Node.js readable stream
 * @param app - Vue application instance
 * @param context - SSR context object
 * @returns Node.js readable stream
 */
function renderToNodeStream(
  app: App,
  context?: SSRContext
): NodeJS.ReadableStream;

/**
 * Render to Web Streams API readable stream
 * @param app - Vue application instance
 * @param context - SSR context object
 * @returns Web ReadableStream
 */
function renderToWebStream(
  app: App,
  context?: SSRContext
): ReadableStream;

Usage Examples:

import { createSSRApp } from "vue";
import { renderToNodeStream, renderToWebStream } from "vue/server-renderer";

const app = createSSRApp(App);

// Node.js stream
const nodeStream = renderToNodeStream(app);
nodeStream.pipe(response);

// Web stream
const webStream = renderToWebStream(app);
const response = new Response(webStream, {
  headers: { 'content-type': 'text/html' }
});

Pipe Functions

/**
 * Pipe rendered content to Node.js writable stream
 * @param app - Vue application instance
 * @param writable - Node.js writable stream
 * @param context - SSR context object
 * @returns Promise that resolves when piping is complete
 */
function pipeToNodeWritable(
  app: App,
  writable: NodeJS.WritableStream,
  context?: SSRContext
): Promise<void>;

/**
 * Pipe rendered content to Web writable stream
 * @param app - Vue application instance
 * @param writable - Web WritableStream
 * @param context - SSR context object
 * @returns Promise that resolves when piping is complete
 */
function pipeToWebWritable(
  app: App,
  writable: WritableStream,
  context?: SSRContext
): Promise<void>;

SSR Context

Context Access

/**
 * Access SSR context in component (only available during SSR)
 * @returns SSR context object or undefined
 */
function useSSRContext<T = Record<string, any>>(): T | undefined;

Usage Example:

import { defineComponent, useSSRContext } from "vue";

export default defineComponent({
  setup() {
    const ssrContext = useSSRContext();
    
    if (ssrContext) {
      // Add data to SSR context
      ssrContext.modules = ssrContext.modules || new Set();
      ssrContext.modules.add('my-component');
    }
    
    return {};
  }
});

Context Interface

interface SSRContext {
  [key: string]: any;
  modules?: Set<string>;
  styles?: string;
  head?: string;
  links?: string;
  prefetch?: string;
  preload?: string;
  teleports?: Record<string, string>;
  __teleportBuffers?: Record<string, string[]>;
}

Hydration Strategies

Control when and how components hydrate on the client-side.

/**
 * Hydrate component when browser becomes idle
 * @param timeout - Timeout in milliseconds (default: 10000)
 * @returns Hydration strategy factory
 */
function hydrateOnIdle(timeout?: number): HydrationStrategy;

/**
 * Hydrate component when it becomes visible
 * @param options - Intersection observer options
 * @returns Hydration strategy factory
 */
function hydrateOnVisible(options?: IntersectionObserverInit): HydrationStrategy;

/**
 * Hydrate component when media query matches
 * @param query - Media query string
 * @returns Hydration strategy factory
 */
function hydrateOnMediaQuery(query: string): HydrationStrategy;

/**
 * Hydrate component on user interaction
 * @param interactions - Event name or array of event names
 * @returns Hydration strategy factory
 */
function hydrateOnInteraction(
  interactions?: keyof HTMLElementEventMap | Array<keyof HTMLElementEventMap>
): HydrationStrategy;

type HydrationStrategy = (
  hydrate: () => void,
  forEachElement: (cb: (el: Element) => any) => void
) => (() => void) | void;

Usage Example:

import { defineAsyncComponent, hydrateOnVisible, hydrateOnIdle } from "vue";

// Hydrate heavy component when visible
const HeavyChart = defineAsyncComponent({
  loader: () => import('./HeavyChart.vue'),
  hydrate: hydrateOnVisible({ rootMargin: '100px' })
});

// Hydrate non-critical component when idle
const Newsletter = defineAsyncComponent({
  loader: () => import('./Newsletter.vue'),
  hydrate: hydrateOnIdle()
});

Internal SSR Helpers

Low-level functions used internally by Vue's SSR compiler (typically not used directly).

/**
 * Render VNode for SSR (internal)
 * @param vnode - VNode to render
 * @param context - SSR context
 * @returns Rendered string
 */
function ssrRenderVNode(
  vnode: VNode,
  context: SSRContext
): string;

/**
 * Render component for SSR (internal)
 * @param comp - Component to render
 * @param props - Component props
 * @param children - Component children
 * @param parentComponent - Parent component instance
 * @param context - SSR context
 * @returns Rendered string
 */
function ssrRenderComponent(
  comp: Component,
  props: any,
  children: any,
  parentComponent: ComponentInternalInstance | null,
  context: SSRContext
): string;

/**
 * Render slot for SSR (internal)
 * @param slots - Slots object
 * @param slotName - Name of slot to render
 * @param slotProps - Props to pass to slot
 * @param fallback - Fallback content
 * @param context - SSR context
 * @returns Rendered string
 */
function ssrRenderSlot(
  slots: Slots,
  slotName: string,
  slotProps: any,
  fallback: (() => string) | null,
  context: SSRContext
): string;

/**
 * Interpolate value for SSR (internal)
 * @param value - Value to interpolate
 * @returns Escaped string
 */
function ssrInterpolate(value: any): string;

/**
 * Render list for SSR (internal)
 * @param source - List source
 * @param renderItem - Function to render each item
 * @returns Rendered string
 */
function ssrRenderList(
  source: any,
  renderItem: (item: any, index: number) => string
): string;

/**
 * Render attributes for SSR (internal)
 * @param attrs - Attributes object
 * @returns Rendered attribute string
 */
function ssrRenderAttrs(attrs: Record<string, any>): string;

/**
 * Render class for SSR (internal)
 * @param value - Class value
 * @returns Rendered class string
 */
function ssrRenderClass(value: any): string;

/**
 * Render style for SSR (internal)
 * @param value - Style value
 * @returns Rendered style string
 */
function ssrRenderStyle(value: any): string;

SSR Application Creation

/**
 * Create SSR-optimized Vue application
 * @param rootComponent - Root component
 * @param rootProps - Root component props
 * @returns SSR app instance
 */
function createSSRApp(
  rootComponent: Component,
  rootProps?: any
): App;

Usage Example:

import { createSSRApp } from "vue";
import App from "./App.vue";

// Create SSR app
const app = createSSRApp(App);

// Configure app for SSR
app.provide('isSSR', true);
app.config.globalProperties.$isServer = true;

export { app };

Advanced SSR Patterns

Async Data Fetching

/**
 * Server prefetch hook for async data loading
 * @param callback - Async prefetch function
 */
function onServerPrefetch(callback: () => Promise<any>): void;

Usage Example:

import { defineComponent, ref, onServerPrefetch } from "vue";

export default defineComponent({
  async setup() {
    const data = ref(null);
    
    // This runs only on server during SSR
    onServerPrefetch(async () => {
      data.value = await fetch('/api/data').then(r => r.json());
    });
    
    return { data };
  }
});

Teleport SSR

Handle teleported content in SSR environments.

/**
 * SSR Teleport context for managing teleported content
 */
interface SSRTeleportContext {
  teleports: Record<string, string>;
  __teleportBuffers: Record<string, string[]>;
}

Usage Example:

import { renderToString, Teleport } from "vue";

const app = createSSRApp({
  template: `
    <div>
      <Teleport to="#modal">
        <div>Modal content</div>
      </Teleport>
    </div>
  `
});

const context = {};
const html = await renderToString(app, context);

// Access teleported content
console.log(context.teleports['#modal']); // <div>Modal content</div>

Hydration Strategies

Modern hydration strategies for optimizing SSR applications with selective and conditional hydration.

Conditional Hydration

/**
 * Hydrate component when browser is idle
 * @param component - Component to hydrate conditionally
 * @returns Wrapped component with idle hydration
 */
function hydrateOnIdle(component: Component): Component;

/**
 * Hydrate component when it becomes visible in viewport
 * @param component - Component to hydrate conditionally
 * @param options - Intersection observer options
 * @returns Wrapped component with visibility-based hydration
 */
function hydrateOnVisible(
  component: Component, 
  options?: IntersectionObserverInit
): Component;

/**
 * Hydrate component when media query matches
 * @param component - Component to hydrate conditionally
 * @param query - CSS media query string
 * @returns Wrapped component with media query hydration
 */
function hydrateOnMediaQuery(component: Component, query: string): Component;

/**
 * Hydrate component on user interaction
 * @param component - Component to hydrate conditionally
 * @param events - Array of event names to trigger hydration
 * @returns Wrapped component with interaction-based hydration
 */
function hydrateOnInteraction(component: Component, events: string[]): Component;

Usage Examples:

import { 
  defineAsyncComponent,
  hydrateOnIdle, 
  hydrateOnVisible, 
  hydrateOnMediaQuery,
  hydrateOnInteraction 
} from "vue";

// Hydrate when browser is idle
const LazyChart = hydrateOnIdle(
  defineAsyncComponent(() => import('./Chart.vue'))
);

// Hydrate when component enters viewport
const LazyImage = hydrateOnVisible(
  defineAsyncComponent(() => import('./LazyImage.vue'))
);

// Hydrate only on desktop
const DesktopSidebar = hydrateOnMediaQuery(
  defineAsyncComponent(() => import('./Sidebar.vue')),
  '(min-width: 768px)'
);

// Hydrate on user interaction
const InteractiveModal = hydrateOnInteraction(
  defineAsyncComponent(() => import('./Modal.vue')),
  ['click', 'touchstart']
);

// Use in template
const App = {
  components: {
    LazyChart,
    LazyImage,
    DesktopSidebar,
    InteractiveModal
  },
  template: `
    <div>
      <LazyChart />
      <LazyImage src="/hero.jpg" />
      <DesktopSidebar />
      <button @click="showModal = true">
        <InteractiveModal v-if="showModal" />
      </button>
    </div>
  `
};

Type Definitions

interface App {
  mount(rootContainer: Element | string): ComponentPublicInstance;
  unmount(): void;
  provide<T>(key: InjectionKey<T> | string, value: T): this;
  component(name: string): Component | undefined;
  component(name: string, component: Component): this;
  directive(name: string): Directive | undefined;
  directive(name: string, directive: Directive): this;
  use(plugin: Plugin, ...options: any[]): this;
  mixin(mixin: ComponentOptions): this;
  version: string;
  config: AppConfig;
}

interface SimpleReadableStream {
  on(event: 'data', callback: (chunk: string) => void): void;
  on(event: 'end', callback: () => void): void;
  on(event: 'error', callback: (error: Error) => void): void;
  push(chunk: string | null): void;
}

interface SSRBuffer {
  hasAsync: boolean;
  buffer: string[];
  promise: Promise<void> | null;
}