Server side rendering, server side generation
This is an advanced use case and assumes you are already familiar with Vue Flow. If you’re new to Vue Flow, check out our getting started guide.
In this guide, you’ll learn how to configure Vue Flow for server-side rendering, enabling you to:
- Generate static HTML diagrams for documentation
- Render Vue Flow diagrams in non-JavaScript environments
- Create dynamic Open Graph images for social media sharing
Why Server-Side Rendering is Complex
To understand why server-side rendering in Vue Flow requires special configuration, let’s look at what Vue Flow typically handles on the client side:
-
Node Dimension Calculation
- Nodes can contain any content, so their dimensions are determined by the browser’s layout engine
- This dynamic sizing isn’t available during server-side rendering
-
Handle Position Detection
- Edge connections require precise handle positions
- These positions are calculated based on CSS layout, which isn’t available on the server
-
Container Size Adaptation
- Vue Flow adapts to its container’s dimensions
- Server-side rendering needs an explicit viewport
Node Dimensions
The most crucial aspect of server-side rendering is specifying node dimensions. On the client, Vue Flow automatically measures nodes and stores dimensions in measured.width and measured.height. For server-side rendering, you must provide these dimensions explicitly using either:
widthandheight: Static dimensions that won’t changeinitialWidthandinitialHeight: Dynamic dimensions that may change after client-side hydration
import type { Node } from '@xyflow/vue';
const nodes: Node[] = [
{
id: '1',
type: 'default',
position: { x: 0, y: 0 },
data: { label: 'Node 1' },
width: 100,
height: 50,
},
];Handle Positions
To render edges on the server, you need to provide handle positions explicitly. On the client, Vue Flow calculates these positions automatically, but for server-side rendering, you must specify them using the handles property:
import type { Node } from '@xyflow/vue';
import { Position } from '@xyflow/vue';
const nodes: Node[] = [
{
id: '1',
type: 'default',
position: { x: 0, y: 0 },
data: { label: 'Node 1' },
width: 100,
height: 50,
handles: [
{
type: 'target',
position: Position.Top,
x: 100 / 2,
y: 0,
},
{
type: 'source',
position: Position.Bottom,
x: 100 / 2,
y: 50,
},
],
},
];Setting the viewport for Server-Side Rendering
Unlike React Flow and Svelte Flow, Vue Flow’s <VueFlow /> component doesn’t expose width
and height props, and fitView relies on measuring the rendered container, which isn’t available on the
server. For server-side rendering, give the wrapping element fixed
dimensions and set an explicit initial transform with the
defaultViewport prop. You can still pass fitView so the flow
re-fits on the client once it is measured after hydration:
<script setup lang="ts">
import { VueFlow } from '@xyflow/vue';
const defaultViewport = { x: 0, y: 0, zoom: 1 };
</script>
<template>
<div style="width: 1000px; height: 500px">
<VueFlow
:nodes="nodes"
:edges="edges"
:default-viewport="defaultViewport"
:min-zoom="0.2"
fit-view
/>
</div>
</template>Generating Static HTML
To create static HTML output, you can use Vue’s server renderer. This generates an HTML string that you can use for static files or HTTP responses:
<script setup lang="ts">
import type { Edge, Node } from '@xyflow/vue';
import { Background, VueFlow } from '@xyflow/vue';
defineProps<{ nodes: Node[]; edges: Edge[] }>();
</script>
<template>
<div style="width: 1000px; height: 500px">
<VueFlow :nodes="nodes" :edges="edges" :min-zoom="0.2" fit-view>
<Background />
</VueFlow>
</div>
</template>import { createSSRApp } from 'vue';
import { renderToString } from 'vue/server-renderer';
import Flow from './Flow.vue';
async function toHTML({ nodes, edges }) {
const app = createSSRApp(Flow, { nodes, edges });
return await renderToString(app);
}