Vue's SSR capabilities provide complete server-side rendering support with streaming, hydration, context management, and multiple output formats for building universal applications.
/**
* 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>/**
* 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 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>;/**
* 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 {};
}
});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[]>;
}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()
});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;/**
* 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 };/**
* 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 };
}
});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>Modern hydration strategies for optimizing SSR applications with selective and 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>
`
};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;
}