Server-Side Rendering
About 1348 wordsAbout 4 min
vueServer-Side RenderingSSRCSR
2025-01-18
SSR (Server-Side Rendering) refers to the technique of rendering page content on the server side and then sending it to the client. Essentially, it involves calling framework-provided methods like renderToString to render the component tree into an HTML string or stream, which is then returned to the frontend for direct use.
Core Process of SSR
Server Rendering
: When a user visits the website, the server requests Vue components and renders them, returning the generated HTML content to the browser.Client Takeover
: After the browser receives the server-rendered HTML, Vue "takes over" the page on the client side, performing client-side mounting and interaction. This step is usually completed through Hydration to ensure consistency between client and server content.
Hydration
: The process of "re-binding" the static HTML page rendered by the server with the client-side JavaScript state and behavior. This process includes:
- Loading static resources like JavaScript.
- Re-binding the component's event listeners to the DOM nodes.
- Restoring the application (routing and state).
- State Restoration: The server saves the final state data as a JSON string in a global variable on the window object and injects it into the HTML. The client reads this variable after receiving the HTML and restores it into the state tool or component.
- Routing Restoration: Both the server and client create routes based on vue-router. The server initializes the route by assigning the history parameter using
createMemoryHistory
. The client assigns it usingcreateWebHistory/createHashHistory
. This way, the server's routing operations will automatically sync to the final routing state after the client mounts the route using app.use.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
// Hydration: Bind the server-rendered HTML with React components
const initialState = window.__INITIAL_STATE__; // Initial state passed from the server
ReactDOM.hydrate(
<App initialState={initialState} />,
document.getElementById('root')
);
- In React, this process is achieved by calling the ReactDOM.hydrate() method.
- In Vue.js, the client application uses the Vue.hydrate() method to handle the binding between page elements and Vue instances.
Hydration Issues and Challenges
Performance
: The hydration process may increase client-side loading time, especially for large applications. Excessive JavaScript code may cause delays, affecting the first screen rendering time.Mismatch Issues
: If the HTML rendered by the server is inconsistent with the rendering of client React components, hydration may fail, causing page flickering or errors. This is usually due to unsynchronized component states, environmental differences, or data inconsistencies.Development Complexity
: Hydration requires ensuring consistent rendering between the server and client, which may require additional configuration and fine-grained management during development, especially in complex application scenarios.
Conditions for Server-Side Rendering
A Server Supporting SSR
: It can be a physical server, cloud server, or virtual host. It needs a runtime environment capable of running backend code (such as Node.js, PHP, Python, Ruby, etc.).Runtime Environment
:- Node.js: If using modern JavaScript frameworks (like Next.js or Nuxt.js) for SSR, Node.js needs to be installed.
- Python: If using Django + template engine, a Python environment is required.
- PHP: If using Laravel or traditional PHP template rendering.
- Java: If using Spring Boot or JSP.
SSR in Vue 3
Vue 3 provides some APIs to help implement server-side rendering. The key steps are as follows:
Create a Vue Server-Side Application
Render the Vue Application to HTML
Handle Client-Side Mounting
Refer to the following example:
// 1. Install the @vue/server-renderer module
// 2. Create an SSR application and return it
import { renderToString } from '@vue/server-renderer';
import { createSSRApp } from 'vue';
import App from './App.vue';
const app = createSSRApp(App);
// Generate the HTML string on the server and prepare to return it
renderToString(app).then((html) => {
console.log(html);
});
// Or return as a stream
const stream = renderToNodeStream(app);
stream.pipe(process.stdout); // Output the stream to standard output or HTTP response
Server-side rendering usually requires two entry files. One for generating HTML on the server and one for client-side hydration.
// server.js
import { createSSRApp } from 'vue';
export async function render(url) {
const app = createSSRApp({
data: () => ({ message: 'Hello from SSR!' }),
template: `<div>{{ message }}</div>`,
});
// Convert the app to an HTML string
const appContent = await renderToString(app);
// Inject pre-fetched data
return `<html>
<body>
<div id="app">${appContent}</div>
<script>window.__INITIAL_STATE__ = ${JSON.stringify({ message: 'Hello from SSR!' })}</script>
</body>
</html>`;
}
// client.js
import { createSSRApp } from 'vue';
const app = createSSRApp({
data: () => window.__INITIAL_STATE__,
template: `<div>{{ message }}</div>`,
});
app.mount('#app');
Implementing SSR with Nuxt 3
Nuxt is a framework in the Vue ecosystem specifically designed for SSR, providing out-of-the-box SSR functionality. Nuxt automatically handles page rendering, routing management, static resource optimization, etc., allowing developers to focus on business logic.
Please refer here
Nuxt Related Issues
Difference between Nuxt.js and Vue.js
: Nuxt.js is a framework built on Vue.js, providing SSR, static site generation, and other features.Rendering Modes Supported by Nuxt.js
:- universal (SSR): Server-side rendering
- spa (Single Page Application): Fully client-side rendering
- static (Static Generation): Generates pure static pages, suitable for SEO and fast loading
How to Customize the Default Layout of Nuxt.js
: Create a layouts/default.vue file to define the default layout.How Nuxt.js Generates Routes
: Automatically generates routes based on the file structure in the pages directory.How to Define Dynamic Routes in Nuxt.js
: Use square brackets to define dynamic parameters in the pages directory.pages/ └── user/ └── [id].vue -> '/user/:id'
How to Implement Route Middleware
: Define middleware in the middleware directory and then use it in pages or globally.// middleware/auth.js export default function ({ store, redirect }) { if (!store.state.authenticated) { return redirect('/login'); } } // nuxt.config.js export default { router: { middleware: ['auth'] } }
Note
In Nuxt.js, middleware is a function. All middleware files are stored in the middleware/ directory, and each middleware is an exported function.
It executes before the page or route switch, used to handle specific logic such as user authentication, redirection, permission checks, etc.
Local Middleware
: Specified in the component usingdefinePageMeta
.Global Middleware
: Specified in nuxt.config.ts.
Parameters and methods accessible in middleware:
- to: Target route object, representing the route the user is about to visit.
- from: Source route object, representing the route the user previously visited.
- navigateTo(): Used to redirect the user to another page.
- abortNavigation(): Terminates the current navigation.
How to Fetch Asynchronous Data in Nuxt.js
: Directly compile asynchronous function interfaces in setup mode.
Performance Optimization for SSR
- Cache HTML content.
- For pages that do not need dynamic updates, use prerendering to generate HTML files during the build process, avoiding server rendering each time.
- Asynchronous component loading: In SSR, use asynchronous component loading as much as possible to load components on demand and reduce the initial JavaScript size of the page.
- Lazy loading routes: Use Vue Router's lazy loading mechanism to load routes and pages on demand, reducing the content loaded on the initial page.
- Tree-shaking and code splitting: Use Webpack or Vite's code splitting and tree-shaking to remove unused code, reduce the size of JavaScript, and improve loading speed.
- Reduce the JavaScript burden on the client: Although SSR provides server-rendered HTML, during the client-side "hydration" process, Vue needs to bind the HTML. If the application's JavaScript is too large, the hydration process may slow down.
- Combination of SSR and CSR: SSR is used for the first screen load to ensure quick display of page content. CSR is used for subsequent navigation and dynamic content, avoiding re-rendering the page for each user interaction and improving user experience.
Note
CSR refers to the browser downloading an empty HTML page (usually an HTML file with the most basic structure), and then the client-side JavaScript code takes over the page rendering, dynamically generating the page content. The page content is generated by JavaScript in the browser, usually through Ajax or Fetch requests to get data from the server.