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 selectHow 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:
- For each component vnode, it creates an instance, runs
setupComponent, and pulls a server-render function. Compiled SSR templates are generated by@vue/compiler-ssrand emit calls to helpers like_push,_renderComponent,_renderSlot. These compose with template literals to build the output string by string. - 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. - For text/interpolation nodes,
ssrInterpolate.tsescapes the value via@vue/shared'sescapeHtml. - For built-ins, the helpers in
helpers/produce the right wrappers —Teleportwrites<!--teleport start-->/<!--teleport end-->markers so client hydration can pick them up;Suspenserenders 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 anduseCssVars.
useSSRContext() (re-exported from runtime-core) lets components read the context.
Integration points
- Reuses
@vue/runtime-core'ssetupComponent,renderComponentRoot, and the component instance machinery. ThessrUtilsexport fromruntime-coreis gated by__SSR__and is the curated entry point. - Imports
@vue/shared'sescapeHtmlfor sanitization. - Imports
vuefor the directive SSR init side effect (sov-showandv-modelwork consistently). - The actual SSR render functions come from
@vue/compiler-ssr(or@vue/compiler-sfcfor.vuefiles compiled withssr: 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 frominternal.tssocompiler-ssrcan reference it. - Streaming bug?
renderToStream.tsis 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.