Frontend Development 18 min read

Understanding Server‑Side Rendering (SSR) with Vue: Principles, Architecture, and Implementation

This article explains the concepts, use cases, advantages, and limitations of server‑side rendering (SSR) for Vue applications, details the Vue SSR architecture and core packages, and provides practical code examples and ready‑to‑use scaffolds for building SSR projects.

政采云技术
政采云技术
政采云技术
Understanding Server‑Side Rendering (SSR) with Vue: Principles, Architecture, and Implementation

Preface

In front‑end development, when first‑screen rendering speed is critical, server‑side rendering (SSR) is often mentioned. This article uses Vue to dissect SSR implementation logic, covering its usage scenarios, core principles, and ready‑to‑use scaffolds.

Server‑Side Rendering

SSR (Server‑Side Rendering) means assembling the page’s HTML on the server, sending it to the browser, and then binding events and state on the client to produce a fully interactive application.

Applicable Scenarios

Better SEO support : Search engines crawl the HTML synchronously, so SSR helps when the page relies on asynchronous data.

Faster time‑to‑content : In slow‑network or low‑performance device contexts, SSR shows the first screen earlier than a full SPA.

Unsuitable Scenarios

Handling universal resources : Only beforeCreate and created lifecycle hooks run in SSR, requiring special handling for third‑party APIs.

Deployment and build configuration : The code must run in a Node.js server environment.

Server‑side caching preparation : High‑traffic scenarios need extra caching strategies, and SSR consumes more CPU.

Vue SSR Implementation Principles

Prerequisites

Component Rendering Based on VNode

VNode is a JavaScript object with strong compatibility, allowing rendering on both server and client. Virtual DOM diffing enables partial rendering and reduces performance loss.

vue‑server‑renderer

This package provides the core SSR capabilities for Vue.

SSR Rendering Architecture

Combining the official diagram and project structure gives a full view of SSR.

src ├── components ├── App.vue ├── app.js ---- common entry ├── entry-client.js ---- runs only in the browser └── entry-server.js ---- runs only on the server

import Vue from 'vue' import App from './App.vue' // Export a factory function that creates a new app instance export function createApp () { const app = new Vue({ render: h => h(App) }) return { app } }

import { createApp } from './app' const { app } = createApp() // #app is the root element app.$mount('#app')

import { createApp } from './app' export default context => { const { app } = createApp() return app }

Server and Client Code Writing Principles

Two principles guide code separation:

Common code: Shared between client and server, configured via webpack resolve.alias.

Non‑common code: Client entry mounts DOM and loads third‑party libraries; server entry only creates the Vue instance.

Two Build Outputs

After webpack bundling, two bundles are produced:

vue‑SSR‑server‑bundle.json { "entry": ..., "files": { // All server‑side code files // Entry file } }

vue‑SSR‑client‑manifest.json { "publicPath": ..., "all": [...], "initial": "html string", "async": [...], "modules": {...} }

vue‑server‑renderer Core

The package focuses on application initialization and output.

Application Initialization

Key steps:

Generate Vue object.

Create renderer with render and templateRenderer objects.

Create sandbox VM and load the entry file.

Handle errors with renderToString and renderToStream promises.

const renderer = require('vue-server-renderer').createRenderer() function createRenderer (ref) { // render: renders HTML components var render = createRenderFunction(modules, directives, isUnaryTag, cache) // templateRenderer: handles template rendering var templateRenderer = new TemplateRenderer({ template, inject, shouldPreload, shouldPrefetch, clientManifest, serializer }) }

function createBundleRunner (entry, files, basedir, runInNewContext) { var evaluate = compileModule(files, basedir, runInNewContext) }

function getCompiledScript (filename) { if (compiledScripts[filename]) return compiledScripts[filename] var code = files[filename] var wrapper = NativeModule.wrap(code) var script = new vm.Script(wrapper, { filename, displayErrors: true }) compiledScripts[filename] = script return script }

function evaluateModule (filename, sandbox, evaluatedFiles) { var script = getCompiledScript(filename) var compiledWrapper = runInNewContext === false ? script.runInThisContext() : script.runInNewContext(sandbox) var m = { exports: {} } var r = function (file) { return require(file) } }

Preventing Cross‑Pollution

Node.js processes run long‑lived, so shared state can leak between requests. Using rendererOptions.runInNewContext (true, false, once) isolates each render.

// rendererOptions.runInNewContext options true: create a new context for each render (isolated but slower) false: reuse the same context (faster, but must avoid state leakage) once: initial context for style collection only

Application Output

During output, SSR focuses on loading script content and template rendering. templateRenderer assembles HTML with resource hints, state, scripts, and styles.

TemplateRenderer.prototype.bindRenderFns = function (context) { var renderer = this ['ResourceHints','State','Scripts','Styles'].forEach(function (type) { context['render' + type] = renderer['render' + type].bind(renderer, context) }) }

TemplateRenderer.prototype.render = function (content, context) { if (!this.parsedTemplate) throw new Error('render cannot be called without a template.') if (typeof this.parsedTemplate === 'function') { return this.parsedTemplate(content, context) } if (this.inject) { return ( this.parsedTemplate.head(context) + (context.head || '') + this.renderResourceHints(context) + this.renderStyles(context) + this.parsedTemplate.neck(context) + content + this.renderState(context) + this.renderScripts(context) + this.parsedTemplate.tail(context) ) } else { // ... } }

Ready‑to‑Use SSR Scaffolds

Popular front‑end stacks provide out‑of‑the‑box SSR frameworks:

React: Next.js

Vue: Nuxt.js

Angular: Nest.js

Conclusion

SSR is a universal rendering technique; its adoption depends on the importance of initial load time for the application. For learning purposes, studying the source helps understand advanced architecture, while ready‑made scaffolds offer a smoother setup experience.

References

Vue SSR Official Site (https://ssr.vuejs.org/zh)

Vue Guide (https://www.w3cschool.cn/vuessr/vuessr-jep83epx.html)

Vue SSR Source Analysis (https://juejin.cn/post/6844903812700831757)

frontendArchitectureSSRVueWeb DevelopmentServer-side Rendering
政采云技术
Written by

政采云技术

ZCY Technology Team (Zero), based in Hangzhou, is a growth-oriented team passionate about technology and craftsmanship. With around 500 members, we are building comprehensive engineering, project management, and talent development systems. We are committed to innovation and creating a cloud service ecosystem for government and enterprise procurement. We look forward to your joining us.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.