Lassen Sie uns tiefer in das Konzept des serverseitigen Renderings (SSR) eintauchen und wie es das Benutzererlebnis Ihrer Webanwendung verbessern kann.
Wenn ein Benutzer Ihre Website besucht, erhält er normalerweise zunächst reines HTML, das dann das Laden zusätzlicher Assets wie JavaScript (z. B. App.js) und CSS (z. B. style.css) auslöst. Dieser traditionelle Ansatz, der oft als clientseitiges Rendering bezeichnet wird, bedeutet, dass der Benutzer warten muss, bis diese Ressourcen heruntergeladen und ausgeführt wurden, bevor er sinnvolle Inhalte sieht. Diese Verzögerung kann zu einer suboptimalen Benutzererfahrung führen, insbesondere für Benutzer mit langsamen Verbindungen oder Geräten.
Serverseitiges Rendering behebt dieses Problem, indem dem Benutzer als Antwort auf seine erste Anfrage eine vollständig gerenderte HTML-Seite gesendet wird. Dieses vorgerenderte HTML enthält das vollständige Markup, sodass der Benutzer den Inhalt sofort sehen kann, ohne auf das Laden und Ausführen von JavaScript warten zu müssen.
Zu den wichtigsten Vorteilen von SSR gehören:
Reduzierte Zeit bis zum größten Contentful Paint (LCP): Der Benutzer sieht den Inhalt viel schneller, da der Server ein vollständiges HTML-Dokument sendet.
Verbesserte SEO: Suchmaschinen können Ihre Inhalte effektiver indizieren, da die Inhalte problemlos in HTML verfügbar sind.
Bessere anfängliche Benutzererfahrung: Benutzer können früher mit dem Lesen und Interagieren mit den Inhalten beginnen, was zu höheren Engagement-Raten führt.
Während SSR den LCP reduzieren kann, kann es die Zeit der Interaktion bis zur nächsten Farbe (INP) verlängern. Dies ist die Zeit, die der Benutzer benötigt, um mit der Seite zu interagieren, nachdem sie geladen wurde. Das Ziel besteht darin, sicherzustellen, dass zu dem Zeitpunkt, an dem der Benutzer sich für eine Interaktion mit der Website entscheidet, z. B. durch Klicken auf eine Schaltfläche, das erforderliche JavaScript im Hintergrund geladen ist, sodass die Interaktion reibungslos und nahtlos verläuft.
Eine schlechte Implementierung von SSR kann dazu führen, dass der Benutzer Inhalte sieht, aber nicht mit ihnen interagieren kann, weil das JavaScript noch nicht geladen wurde. Dies kann frustrierender sein, als zunächst darauf zu warten, dass die gesamte Seite geladen wird. Daher ist es wichtig, die Leistungskennzahlen kontinuierlich zu überwachen und zu messen, um sicherzustellen, dass SSR das Benutzererlebnis wirklich verbessert.
Wir unterteilen dies in einige Schritte:
Wir beginnen mit der Erstellung einer ClientApp.jsx-Datei, die alle browserspezifischen Funktionen übernimmt.
// ClientApp.jsx import { hydrateRoot } from 'react-dom/client'; import { BrowserRouter } from 'react-router-dom'; import App from './App';
Hier importieren wir hydrateRoot von React-Dom/Client, BrowserRouter von React-Router-Dom und unsere Haupt-App-Komponente.
// ClientApp.jsx // Hydrate the root element with our app hydrateRoot(document.getElementById('root'), <BrowserRouter> <App /> </BrowserRouter> );
Wir verwenden hydrateRoot, um unsere App auf der Clientseite zu rendern, indem wir das Root-Element angeben und unsere App mit BrowserRouter umschließen. Dieses Setup stellt sicher, dass der gesamte browserspezifische Code hier bleibt.
Als nächstes müssen wir unsere App.jsx ändern.
// App.jsx import React from 'react'; // Exporting the App component export default function App() { return ( <div> <h1>Welcome to My SSR React App!</h1> </div> ); }
Hier halten wir unsere App-Komponente zu Demonstrationszwecken einfach. Wir exportieren es, damit es sowohl in Client- als auch in Serverumgebungen verwendet werden kann.
Als nächstes müssen wir index.html aktualisieren, um ClientApp.jsx anstelle von App.jsx zu laden, und außerdem das Parsing-Token hinzufügen, um die HTML-Datei auf dem Server aufzuteilen, damit wir den Inhalt im Root-Div streamen können.
<!doctype html> <html lang="en"> <head> <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> </head> <body> <div id="root"><!--not rendered--></div> <script type="module" src="./src/ClientApp.jsx"></script> </body> </html>
Jetzt erstellen wir eine ServerApp.jsx-Datei, um die serverseitige Rendering-Logik zu verwalten.
// 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 /> </StaticRouter>, opts ); return stream; }
Wir müssen unsere Build-Skripte in package.json aktualisieren, um sowohl die Client- als auch die Server-Bundles zu erstellen.
{ "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" }
Hier definieren wir separate Build-Skripte für den Client und den Server. Das build:client-Skript erstellt das Client-Bundle, während das build:server-Skript das Server-Bundle mithilfe von ServerApp.jsx erstellt. Das Build-Skript führt beide Build-Schritte aus und das Startskript führt den Server mithilfe von server.js aus (das im nächsten Schritt erstellt wird).
∴Entfernen Sie tsc aus dem Client- und Server-Build, wenn Sie TypeScript nicht verwenden.
Zuletzt konfigurieren wir unseren Knotenserver 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.
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.
Das obige ist der detaillierte Inhalt vonEin Leitfaden zum serverseitigen Rendering (SSR) mit Vite und React.js. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!