Open-Source Wikis

/

Vue.js

/

Packages

/

server-renderer

vuejs/core

server-renderer

Active contributors: Evan You, daiwei, edison

Purpose

@vue/server-renderer runs Vue components on the server and produces an HTML string. It supports synchronous rendering (renderToString), Node.js streams (renderToNodeStream, pipeToNodeWritable), Web streams (renderToWebStream, pipeToWebWritable), and a low-level simple-stream interface (renderToSimpleStream). The render functions it consumes are produced by @vue/compiler-ssr, not the regular template compiler.

Directory layout

packages/server-renderer/src/
├── index.ts              # public exports + initDirectivesForSSR side effect
├── render.ts             # the recursive renderComponentSubTree (~11KB, the spine)
├── renderToString.ts     # renderToString public entry
├── renderToStream.ts     # all stream variants
├── internal.ts           # types re-exported for compiler-ssr generated code
└── helpers/
    ├── ssrRenderAttrs.ts          # serialize props as HTML attributes
    ├── ssrRenderClass.ts          # class normalization for SSR
    ├── ssrRenderStyle.ts          # style normalization for SSR
    ├── ssrRenderComponent.ts      # render a component vnode in SSR mode
    ├── ssrRenderSlot.ts           # SSR slot rendering
    ├── ssrRenderTeleport.ts       # SSR Teleport handling (writes a marker block)
    ├── ssrRenderSuspense.ts       # SSR Suspense handling (renders fallback)
    ├── ssrInterpolate.ts          # {{ … }} → escaped string
    └── ssrLooseContains.ts        # for SSR v-model select

How it works

The package's index.ts does an import 'vue' at the top so it can call initDirectivesForSSR() — the function that registers SSR-side renderers for v-model and v-show. Without this side effect the directives would render differently on the server vs. the client.

render.ts walks the component tree:

  1. For each component vnode, it creates an instance, runs setupComponent, and pulls a server-render function. Compiled SSR templates are generated by @vue/compiler-ssr and emit calls to helpers like _push, _renderComponent, _renderSlot. These compose with template literals to build the output string by string.
  2. For host elements, props are serialized via ssrRenderAttrs.ts (which normalizes class/style and skips DOM-prop-only attributes), the open tag is pushed, then children render recursively, then the close tag is pushed.
  3. For text/interpolation nodes, ssrInterpolate.ts escapes the value via @vue/shared's escapeHtml.
  4. For built-ins, the helpers in helpers/ produce the right wrappers — Teleport writes <!--teleport start-->/<!--teleport end--> markers so client hydration can pick them up; Suspense renders the fallback if any pending dependency exists.

Async components (defineAsyncComponent) are awaited at the level of renderComponentSubTree, which is why renderToString itself returns a Promise.

Entry points

API File Description
renderToString(input, ctx?) packages/server-renderer/src/renderToString.ts The synchronous-ish API. Returns Promise<string>. input is either a VNode or an App. ctx is the SSR context bag.
renderToNodeStream(input, ctx?) packages/server-renderer/src/renderToStream.ts Returns a Node Readable stream. Internally uses renderToSimpleStream.
pipeToNodeWritable(input, ctx, writable) packages/server-renderer/src/renderToStream.ts Pushes chunks directly into a Writable.
renderToWebStream(input, ctx?) packages/server-renderer/src/renderToStream.ts Returns a ReadableStream (Web).
pipeToWebWritable(input, ctx, writable) packages/server-renderer/src/renderToStream.ts Pushes chunks into a WritableStream.
renderToSimpleStream(input, ctx, stream) packages/server-renderer/src/renderToStream.ts Lowest-level stream API — accepts a SimpleReadable like { push, destroy }. The other stream APIs are thin wrappers around this.

SSRContext

The SSRContext (render.ts) is a per-render bag the server caller can pass in to collect side effects:

  • _teleports — a record of teleport-target → rendered-string. The host application can splice these into the right place in the final HTML.
  • __teleportBuffers (internal) — tracks pending teleport content during render.
  • modules, cssVars, etc. — set by SFC <script> modules and useCssVars.

useSSRContext() (re-exported from runtime-core) lets components read the context.

Integration points

  • Reuses @vue/runtime-core's setupComponent, renderComponentRoot, and the component instance machinery. The ssrUtils export from runtime-core is gated by __SSR__ and is the curated entry point.
  • Imports @vue/shared's escapeHtml for sanitization.
  • Imports vue for the directive SSR init side effect (so v-show and v-model work consistently).
  • The actual SSR render functions come from @vue/compiler-ssr (or @vue/compiler-sfc for .vue files compiled with ssr: true). This package provides the helpers those compiled functions call.

Notes on hydration

This package only produces the SSR string. The client side is in runtime-core's hydration.ts. Both sides must agree on:

  • HTML structure (no extra/fewer nodes).
  • Attribute ordering and presence (boolean attributes, data-v-app, data-server-rendered).
  • Teleport markers.

Mismatches are surfaced as dev warnings, with details controlled by the __VUE_PROD_HYDRATION_MISMATCH_DETAILS__ flag.

For the full picture, see features/server-side-rendering and features/hydration.

Entry points for modification

  • New SSR helper that the compiler emits? Add it under helpers/ and re-export from internal.ts so compiler-ssr can reference it.
  • Streaming bug? renderToStream.ts is the right file. The stream APIs share a common buffer model — a fix usually applies to all of them.
  • Teleport/Suspense semantics? Coordinate with runtime-core's built-in component code; both sides have to agree on the marker format.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

server-renderer – Vue.js wiki | Factory