Vue 2 Server Renderer
The `vue-server-renderer` package provides Node.js server-side rendering (SSR) capabilities for applications built with Vue.js 2.x. As of its final release, v2.7.16 ("Swan Song"), this package is intrinsically tied to Vue 2, which reached its End of Life (EOL) on December 31st, 2023. Consequently, `vue-server-renderer` is no longer actively maintained and will not receive further updates, including bug fixes or security patches. Its primary function was to enable universal Vue 2 applications, improving initial page load times and SEO by delivering fully-rendered HTML from the server. For any ongoing or new projects, developers are strongly advised to migrate to Vue 3 and utilize its corresponding SSR solution, `@vue/server-renderer`, which is under active development and support.
Common errors
-
ReferenceError: window is not defined
cause Attempting to access browser-specific global objects (like `window`, `document`, `navigator`) during server-side rendering.fixWrap code accessing browser globals within `if (typeof window !== 'undefined')` checks or defer execution to client-side lifecycle hooks (e.g., `mounted`). -
TypeError: Cannot read property 'replace' of undefined at normalizeFile
cause This error can occur in specific setups, often related to Webpack configurations (e.g., `SSRClientWebpackPlugin`) or when referencing `process` variables in a way that interferes with internal `vue-server-renderer` logic.fixReview Webpack configurations for SSR-related plugins and ensure `process.env` variables are handled correctly. Isolate and test the component causing the issue; sometimes removing an import might reveal the root cause. -
Unexpected token
cause Invalid syntax in templates provided to the renderer, commonly using triple curly braces `{{{ }}` for string interpolation instead of double `{{ }}`.fixEnsure correct Vue 2 template syntax. For simple text interpolation, use `{{ variable }}`. Triple curly braces `{{{ }}}` were used for unescaped HTML in Vue 1 but are not valid for interpolation in Vue 2, which uses `v-html` for raw HTML. -
The client-side rendered virtual DOM tree is not matching server-rendered content.
cause A hydration mismatch where the Vue application's client-side output differs from the HTML sent by the server.fixCarefully inspect component logic that might produce different output between server and client, especially conditional rendering, `v-if`/`v-show` conditions, and initial data states. Ensure consistent data fetching and state serialization across environments.
Warnings
- breaking Vue 2, and consequently `vue-server-renderer`, reached End of Life (EOL) on December 31st, 2023. The package is no longer maintained and will not receive any further bug fixes, security updates, or feature enhancements.
- breaking Migration from Vue 2's `vue-server-renderer` to Vue 3's `@vue/server-renderer` involves significant API changes. For instance, `createBundleRenderer` is not available in Vue 3, and the rendering process has evolved.
- gotcha Attempting to use browser-specific global APIs (e.g., `window`, `document`, `localStorage`) directly in your Vue components during server-side rendering will result in `ReferenceError: window is not defined` or similar errors, as Node.js environments do not have these globals.
- gotcha Hydration mismatches can occur when the client-side rendered virtual DOM tree does not precisely match the HTML structure generated by the server. This can lead to re-rendering of parts of the page, incorrect behavior, or console errors like 'Mismatching childNodes vs. VNodes'.
Install
-
npm install vue-server-renderer -
yarn add vue-server-renderer -
pnpm add vue-server-renderer
Imports
- createRenderer
const { createRenderer } = require('vue-server-renderer')import { createRenderer } from 'vue-server-renderer' - createBundleRenderer
const { createBundleRenderer } = require('vue-server-renderer')import { createBundleRenderer } from 'vue-server-renderer' - renderToString (method)
renderer.renderToString(vm, context)
Quickstart
import Vue from 'vue';
import { createRenderer } from 'vue-server-renderer';
// 1. Create a Vue 2 application instance
const app = new Vue({
template: `
<div id="app">
<h1>Welcome to Vue 2 SSR!</h1>
<p>This message: {{ serverMessage }}</p>
<button @click="increment">Client-side interaction: {{ count }}</button>
<p><em>(Button functionality requires client-side hydration)</em></p>
</div>
`,
data() {
return {
serverMessage: 'Rendered on the server.',
count: 0
};
},
methods: {
increment() {
this.count++;
console.log('Client-side count:', this.count); // This log only appears in browser
}
}
});
// 2. Create a renderer instance
const renderer = createRenderer();
// 3. Render the Vue app to an HTML string
renderer.renderToString(app)
.then(html => {
const fullHtml = `
<!DOCTYPE html>
<html>
<head>
<title>Vue 2 SSR Example</title>
<style>body { font-family: sans-serif; margin: 20px; }</style>
</head>
<body>
${html}
<!-- In a real application, you would hydrate this on the client:
<script>
// window.__INITIAL_STATE__ = { serverMessage: '...', count: 0 };
// new Vue({ el: '#app', data: window.__INITIAL_STATE__ });
</script> -->
</body>
</html>
`;
console.log(fullHtml);
})
.catch(err => {
console.error('Error during Vue 2 SSR:', err);
process.exit(1);
});