Let’s dive deeper into the concept of server-side rendering (SSR) and how it can enhance the user experience of your web application.
The Concept of Server-Side Rendering
When a user visits your website, they typically receive bare HTML initially, which then triggers the loading of additional assets like JavaScript (e.g., App.js) and CSS (e.g., style.css). This traditional approach, often referred to as client-side rendering, means that the user must wait for these resources to download and execute before seeing any meaningful content. This delay can lead to a suboptimal user experience, especially for users on slow connections or devices.
Server-side rendering addresses this issue by sending the user a fully rendered HTML page in response to their initial request. This pre-rendered HTML includes the complete markup, allowing the user to see the content immediately without waiting for JavaScript to load and execute.
The key benefits of SSR include:
Reduced Time to Largest Contentful Paint (LCP): The user sees the content much faster because the server sends a complete HTML document.
Improved SEO: Search engines can index your content more effectively since the content is readily available in HTML.
Better Initial User Experience: Users can start reading and interacting with the content sooner, leading to higher engagement rates.
Balancing Performance Metrics
While SSR can reduce the LCP, it might increase the time of Interaction to Next Paint (INP). This is the time it takes for the user to interact with the page after it has loaded. The goal is to ensure that by the time the user decides to interact with the site, such as clicking a button, the necessary JavaScript has loaded in the background, making the interaction smooth and seamless.
A poor implementation of SSR can lead to a scenario where the user sees content but can't interact with it because the JavaScript hasn’t loaded yet. This can be more frustrating than waiting for the entire page to load initially. Therefore, it's crucial to continuously monitor and measure performance metrics to ensure that SSR is genuinely improving the user experience.
Setting Up SSR in Vite and React.js
We'll break this down into a few steps:
- Create a ClientApp Component
- Update index.html
- Create a ServerApp Component
- Set Up the Build Scripts
- Configure the Node Server
1. Create a ClientApp Component
We'll start by creating a ClientApp.jsx file, which will handle all the browser-specific functionality.
// ClientApp.jsx import { hydrateRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './App';
Here, we import hydrateRoot from react-dom/client, BrowserRouter from react-router-dom, and our main App component.
// ClientApp.jsx // Hydrate the root element with our app hydrateRoot(document.getElementById('root'), <browserrouter> <app></app> </browserrouter> );
We use hydrateRoot to render our app on the client side, specifying the root element and wrapping our App with BrowserRouter. This setup ensures all browser-specific code stays here.
Next, we need to modify our App.jsx.
// App.jsx import React from 'react'; // Exporting the App component export default function App() { return ( <div> <h1 id="Welcome-to-My-SSR-React-App">Welcome to My SSR React App!</h1> </div> ); }
Here, we keep our App component simple for demonstration purposes. We export it so it can be used in both client and server environments.
2. Update index.html
Next, we need to update index.html to load ClientApp.jsx instead of App.jsx and also add the parsing token to split the HTML file in the server, so we can stream the content in the root div.
<meta charset="UTF-8"> <link rel="icon" type="image/svg+xml" href="./vite.svg"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Vite + React + TS</title> <div id="root"><!--not rendered--></div> <script type="module" src="./src/ClientApp.jsx"></script>
3. Create a ServerApp Component
Now, let's create a ServerApp.jsx file to handle the server-side rendering logic.
// ServerApp.jsx import { renderToPipeableStream } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom/server'; import App from './App'; // Export a function to render the app export default function render(url, opts) { // Create a stream for server-side rendering const stream = renderToPipeableStream( <staticrouter location="{url}"> <app></app> </staticrouter>, opts ); return stream; }
4. Set Up the Build Scripts
We'll need to update our build scripts in package.json to build both the client and server bundles.
{ "scripts": { "build:client": "tsc vite build --outDir ../dist/client", "build:server": "tsc vite build --outDir ../dist/server --ssr ServerApp.jsx", "build": "npm run build:client && npm run build:server", "start": "node server.js" }, "type": "module" }
Here, we define separate build scripts for the client and server. The build:client script builds the client bundle, while the build:server script builds the server bundle using ServerApp.jsx. The build script runs both build steps, and the start script runs the server using server.js (which will be created in the next step).
∴ Remove tsc from the client and server build if you are not using TypeScript.
5. Configure the Node Server
Finally, let's configure our Node server in server.js.
// server.js import express from 'express'; import fs from 'fs'; import path from 'path'; import { fileURLToPath } from 'url'; import renderApp from './dist/server/ServerApp.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const PORT = process.env.PORT || 3001; // Read the built HTML file const html = fs.readFileSync(path.resolve(__dirname, './dist/client/index.html')).toString(); const [head, tail] = html.split('<!--not rendered-->'); const app = express(); // Serve static assets app.use('/assets', express.static(path.resolve(__dirname, './dist/client/assets'))); // Handle all other routes with server-side rendering app.use((req, res) => { res.write(head); const stream = renderApp(req.url, { onShellReady() { stream.pipe(res); }, onShellError(err) { console.error(err); res.status(500).send('Internal Server Error'); }, onAllReady() { res.write(tail); res.end(); }, onError(err) { console.error(err); } }); }); app.listen(PORT, () => { console.log(`Listening on http://localhost:${PORT}`); });
In this file, we set up an Express server to handle static assets and server-side rendering. We read the built index.html file and split it into head and tail parts. When a request is made, we immediately send the head part, then pipe the stream from renderApp to the response, and finally send the tail part once the stream is complete.
By following these steps, we enable server-side rendering in our React application, providing a faster and more responsive user experience. The client receives a fully rendered page initially, and the JavaScript loads in the background, making the app interactive.
Conclusion
By implementing server-side rendering (SSR) in our React application, we can significantly improve the initial load time and provide a better user experience. The steps involved include creating separate components for client and server rendering, updating our build scripts, and configuring an Express server to handle SSR. This setup ensures that users receive a fully rendered HTML page on the first request, while JavaScript loads in the background, making the application interactive seamlessly. This approach not only enhances the perceived performance but also provides a robust foundation for building performant and scalable React applications.
The above is the detailed content of A Guide to Server-Side Rendering (SSR) with Vite and React.js. For more information, please follow other related articles on the PHP Chinese website!

The differences in performance and efficiency between Python and JavaScript are mainly reflected in: 1) As an interpreted language, Python runs slowly but has high development efficiency and is suitable for rapid prototype development; 2) JavaScript is limited to single thread in the browser, but multi-threading and asynchronous I/O can be used to improve performance in Node.js, and both have advantages in actual projects.

JavaScript originated in 1995 and was created by Brandon Ike, and realized the language into C. 1.C language provides high performance and system-level programming capabilities for JavaScript. 2. JavaScript's memory management and performance optimization rely on C language. 3. The cross-platform feature of C language helps JavaScript run efficiently on different operating systems.

JavaScript runs in browsers and Node.js environments and relies on the JavaScript engine to parse and execute code. 1) Generate abstract syntax tree (AST) in the parsing stage; 2) convert AST into bytecode or machine code in the compilation stage; 3) execute the compiled code in the execution stage.

The future trends of Python and JavaScript include: 1. Python will consolidate its position in the fields of scientific computing and AI, 2. JavaScript will promote the development of web technology, 3. Cross-platform development will become a hot topic, and 4. Performance optimization will be the focus. Both will continue to expand application scenarios in their respective fields and make more breakthroughs in performance.

Both Python and JavaScript's choices in development environments are important. 1) Python's development environment includes PyCharm, JupyterNotebook and Anaconda, which are suitable for data science and rapid prototyping. 2) The development environment of JavaScript includes Node.js, VSCode and Webpack, which are suitable for front-end and back-end development. Choosing the right tools according to project needs can improve development efficiency and project success rate.

Yes, the engine core of JavaScript is written in C. 1) The C language provides efficient performance and underlying control, which is suitable for the development of JavaScript engine. 2) Taking the V8 engine as an example, its core is written in C, combining the efficiency and object-oriented characteristics of C. 3) The working principle of the JavaScript engine includes parsing, compiling and execution, and the C language plays a key role in these processes.

JavaScript is at the heart of modern websites because it enhances the interactivity and dynamicity of web pages. 1) It allows to change content without refreshing the page, 2) manipulate web pages through DOMAPI, 3) support complex interactive effects such as animation and drag-and-drop, 4) optimize performance and best practices to improve user experience.

C and JavaScript achieve interoperability through WebAssembly. 1) C code is compiled into WebAssembly module and introduced into JavaScript environment to enhance computing power. 2) In game development, C handles physics engines and graphics rendering, and JavaScript is responsible for game logic and user interface.


Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

WebStorm Mac version
Useful JavaScript development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

PhpStorm Mac version
The latest (2018.2.1) professional PHP integrated development tool

Dreamweaver CS6
Visual web development tools

SAP NetWeaver Server Adapter for Eclipse
Integrate Eclipse with SAP NetWeaver application server.
