Erweiterte React SSR-Techniken mit Streaming und dynamischen Daten
Wenn Ihre Anwendung wächst, wachsen auch die Herausforderungen. Um an der Spitze zu bleiben, ist die Beherrschung fortschrittlicher SSR-Techniken für die Bereitstellung eines nahtlosen und leistungsstarken Benutzererlebnisses unerlässlich.
Nachdem ich im vorherigen Artikel eine Grundlage für serverseitiges Rendering in React-Projekten geschaffen habe, freue ich mich, Ihnen Funktionen vorstellen zu können, die Ihnen dabei helfen können, die Skalierbarkeit von Projekten aufrechtzuerhalten, Daten effizient vom Server auf den Client zu laden und Hydratationsprobleme zu lösen.
Inhaltsverzeichnis
- Was ist Streaming in SSR?
- Lazy Loading und SSR
-
Implementierung von Streaming mit Lazy Loading
- React-Komponenten aktualisieren
- Aktualisieren des Servers für Streaming
-
Server-zu-Client-Daten
- Übergabe von Daten an den Server
- Umgebungsvariablen auf dem Client verarbeiten
-
Probleme mit der Flüssigkeitszufuhr
- Beispielszenario
- Behebung von Flüssigkeitsproblemen
- Fazit
Was ist Streaming in SSR?
Streaming beim serverseitigen Rendering (SSR) ist eine Technik, bei der der Server Teile der HTML-Seite in Blöcken an den Browser sendet, während sie generiert werden, anstatt darauf zu warten, dass die gesamte Seite fertig ist bevor Sie es ausliefern. Dadurch kann der Browser sofort mit dem Rendern von Inhalten beginnen, was die Ladezeiten und die Leistung des Benutzers verbessert.
Streaming ist besonders effektiv für:
- Große Seiten: Das Generieren des gesamten HTML-Codes kann viel Zeit in Anspruch nehmen.
- Dynamischer Inhalt: Wenn Teile der Seite von externen API-Aufrufen oder dynamisch generierten Blöcken abhängen.
- Anwendungen mit hohem Datenverkehr: Zur Reduzierung der Serverlast und Latenz bei Spitzenauslastung.
Streaming schließt die Lücke zwischen traditionellem SSR und moderner clientseitiger Interaktivität und stellt sicher, dass Benutzer aussagekräftige Inhalte schneller sehen, ohne Kompromisse bei der Leistung einzugehen.
Lazy Loading und SSR
Lazy Loading ist eine Technik, die das Laden von Komponenten oder Modulen verzögert, bis sie tatsächlich benötigt werden, wodurch die anfängliche Ladezeit verkürzt und die Leistung verbessert wird. In Kombination mit SSR kann Lazy Loading sowohl die Server- als auch die Client-Arbeitslast erheblich optimieren.
Lazy Loading basiert auf React.lazy, das Komponenten dynamisch als Promises importiert. Im herkömmlichen SSR erfolgt das Rendering synchron, was bedeutet, dass der Server alle Promises auflösen muss, bevor er den vollständigen HTML-Code generiert und an den Browser sendet.
Streaming löst diese Herausforderungen, indem es dem Server ermöglicht, HTML in Blöcken zu senden, während Komponenten gerendert werden. Durch diesen Ansatz kann der Suspense-Fallback sofort an den Browser gesendet werden, sodass Benutzer frühzeitig aussagekräftige Inhalte sehen. Wenn verzögert geladene Komponenten aufgelöst werden, wird ihr gerenderter HTML-Code schrittweise an den Browser gestreamt und ersetzt so nahtlos den Fallback-Inhalt. Dadurch wird eine Blockierung des Rendering-Prozesses vermieden, Verzögerungen reduziert und die wahrgenommene Ladezeit verbessert.
Implementierung von Streaming mit Lazy Loading
Dieser Leitfaden baut auf Konzepten auf, die im vorherigen Artikel Erstellung produktionsbereiter SSR-React-Anwendungen vorgestellt wurden, den Sie unten verlinkt finden. Um SSR mit React zu ermöglichen und verzögert geladene Komponenten zu unterstützen, werden wir mehrere Updates sowohl an den React-Komponenten als auch am Server vornehmen.
Aktualisieren von Reaktionskomponenten
Server-Einstiegspunkt
Die renderToString-Methode von React wird üblicherweise für SSR verwendet, sie wartet jedoch, bis der gesamte HTML-Inhalt fertig ist, bevor sie ihn an den Browser sendet. Durch den Wechsel zu renderToPipeableStream können wir Streaming aktivieren, das Teile des HTML sendet, während sie generiert werden.
// ./src/entry-server.tsx import { renderToPipeableStream, RenderToPipeableStreamOptions } from 'react-dom/server' import App from './App' export function render(options?: RenderToPipeableStreamOptions) { return renderToPipeableStream(<App />, options) }
Erstellen einer Lazy-Loaded-Komponente
In diesem Beispiel erstellen wir eine einfache Kartenkomponente, um das Konzept zu demonstrieren. In Produktionsanwendungen wird diese Technik typischerweise bei größeren Modulen oder ganzen Seiten verwendet, um die Leistung zu optimieren.
// ./src/Card.tsx import { useState } from 'react' function Card() { const [count, setCount] = useState(0) return ( <div className="card"> <button onClick={() => setCount((count) => count + 1)}> count is {count} </button> <p> Edit <code>src/App.tsx</code> and save to test HMR </p> </div> ) } export default Card
Verwenden der Lazy-Loaded-Komponente in der App
Um die Lazy-Loaded-Komponente zu verwenden, importieren Sie sie dynamisch mit React.lazy und umschließen Sie sie mit Suspense, um während des Ladens eine Fallback-Benutzeroberfläche bereitzustellen
// ./src/App.tsx import { lazy, Suspense } from 'react' import reactLogo from './assets/react.svg' import viteLogo from '/vite.svg' import './App.css' const Card = lazy(() => import('./Card')) function App() { return ( <> <div> <a href="https://vite.dev" target="_blank"> <img src={viteLogo} className="logo" alt="Vite logo" /> </a> <a href="https://react.dev" target="_blank"> <img src={reactLogo} className="logo react" alt="React logo" /> </a> </div> <h1>Vite + React</h1> <Suspense fallback='Loading...'> <Card /> </Suspense> <p className="read-the-docs"> Click on the Vite and React logos to learn more </p> </> ) } export default App
Aktualisieren des Servers für Streaming
Um Streaming zu ermöglichen, müssen sowohl die Entwicklungs- als auch die Produktionseinstellungen einen konsistenten HTML-Rendering-Prozess unterstützen. Da der Prozess für beide Umgebungen derselbe ist, können Sie eine einzige wiederverwendbare Funktion erstellen, um Streaming-Inhalte effektiv zu verarbeiten.
Erstellen einer Stream-Content-Funktion
// ./server/constants.ts export const ABORT_DELAY = 5000
Die streamContent-Funktion initiiert den Rendering-Prozess, schreibt inkrementelle HTML-Blöcke in die Antwort und stellt eine ordnungsgemäße Fehlerbehandlung sicher.
// ./server/streamContent.ts import { Transform } from 'node:stream' import { Request, Response, NextFunction } from 'express' import { ABORT_DELAY, HTML_KEY } from './constants' import type { render } from '../src/entry-server' export type StreamContentArgs = { render: typeof render html: string req: Request res: Response next: NextFunction } export function streamContent({ render, html, res }: StreamContentArgs) { let renderFailed = false // Initiates the streaming process by calling the render function const { pipe, abort } = render({ // Handles errors that occur before the shell is ready onShellError() { res.status(500).set({ 'Content-Type': 'text/html' }).send('<pre class="brush:php;toolbar:false">Something went wrong') }, // Called when the shell (initial HTML) is ready for streaming onShellReady() { res.status(renderFailed ? 500 : 200).set({ 'Content-Type': 'text/html' }) // Split the HTML into two parts using the placeholder const [htmlStart, htmlEnd] = html.split(HTML_KEY) // Write the starting part of the HTML to the response res.write(htmlStart) // Create a transform stream to handle the chunks of HTML from the renderer const transformStream = new Transform({ transform(chunk, encoding, callback) { // Write each chunk to the response res.write(chunk, encoding) callback() }, }) // When the streaming is finished, write the closing part of the HTML transformStream.on('finish', () => { res.end(htmlEnd) }) // Pipe the render output through the transform stream pipe(transformStream) }, onError(error) { // Logs errors encountered during rendering renderFailed = true console.error((error as Error).stack) }, }) // Abort the rendering process after a delay to avoid hanging requests setTimeout(abort, ABORT_DELAY) }
Entwicklungskonfiguration aktualisieren
// ./server/dev.ts import { Application } from 'express' import fs from 'fs' import path from 'path' import { StreamContentArgs } from './streamContent' const HTML_PATH = path.resolve(process.cwd(), 'index.html') const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'src/entry-server.tsx') // Add to args the streamContent callback export async function setupDev(app: Application, streamContent: (args: StreamContentArgs) => void) { const vite = await ( await import('vite') ).createServer({ root: process.cwd(), server: { middlewareMode: true }, appType: 'custom', }) app.use(vite.middlewares) app.get('*', async (req, res, next) => { try { let html = fs.readFileSync(HTML_PATH, 'utf-8') html = await vite.transformIndexHtml(req.originalUrl, html) const { render } = await vite.ssrLoadModule(ENTRY_SERVER_PATH) // Use the same callback for production and development process streamContent({ render, html, req, res, next }) } catch (e) { vite.ssrFixStacktrace(e as Error) console.error((e as Error).stack) next(e) } }) }
Aktualisierung der Produktionskonfiguration
// ./server/prod.ts import { Application } from 'express' import fs from 'fs' import path from 'path' import compression from 'compression' import sirv from 'sirv' import { StreamContentArgs } from './streamContent' const CLIENT_PATH = path.resolve(process.cwd(), 'dist/client') const HTML_PATH = path.resolve(process.cwd(), 'dist/client/index.html') const ENTRY_SERVER_PATH = path.resolve(process.cwd(), 'dist/ssr/entry-server.js') // Add to Args the streamContent callback export async function setupProd(app: Application, streamContent: (args: StreamContentArgs) => void) { app.use(compression()) app.use(sirv(CLIENT_PATH, { extensions: [] })) app.get('*', async (req, res, next) => { try { const html = fs.readFileSync(HTML_PATH, 'utf-8') const { render } = await import(ENTRY_SERVER_PATH) // Use the same callback for production and development process streamContent({ render, html, req, res, next }) } catch (e) { console.error((e as Error).stack) next(e) } }) }
Aktualisieren des Express-Servers
Übergeben Sie die streamContent-Funktion an jede Konfiguration:
// ./server/app.ts import express from 'express' import { PROD, APP_PORT } from './constants' import { setupProd } from './prod' import { setupDev } from './dev' import { streamContent } from './streamContent' export async function createServer() { const app = express() if (PROD) { await setupProd(app, streamContent) } else { await setupDev(app, streamContent) } app.listen(APP_PORT, () => { console.log(`http://localhost:${APP_PORT}`) }) } createServer()
Nach der Implementierung dieser Änderungen wird Ihr Server:
- Streamen Sie HTML schrittweise an den Browser und verkürzen Sie so die Zeit bis zum ersten Malen.
- Verarbeiten Sie nahtlos geladene Komponenten und verbessern Sie so sowohl die Leistung als auch das Benutzererlebnis.
Server-zu-Client-Daten
Bevor Sie HTML an den Client senden, haben Sie die volle Kontrolle über das vom Server generierte HTML. Dadurch können Sie die Struktur dynamisch ändern, indem Sie nach Bedarf Tags, Stile, Links oder andere Elemente hinzufügen.
Eine besonders wirkungsvolle Technik ist das Einfügen eines

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen











Python eignet sich besser für Anfänger mit einer reibungslosen Lernkurve und einer kurzen Syntax. JavaScript ist für die Front-End-Entwicklung mit einer steilen Lernkurve und einer flexiblen Syntax geeignet. 1. Python-Syntax ist intuitiv und für die Entwicklung von Datenwissenschaften und Back-End-Entwicklung geeignet. 2. JavaScript ist flexibel und in Front-End- und serverseitiger Programmierung weit verbreitet.

Zu den Hauptanwendungen von JavaScript in der Webentwicklung gehören die Interaktion der Clients, die Formüberprüfung und die asynchrone Kommunikation. 1) Dynamisches Inhaltsaktualisierung und Benutzerinteraktion durch DOM -Operationen; 2) Die Kundenüberprüfung erfolgt vor dem Einreichung von Daten, um die Benutzererfahrung zu verbessern. 3) Die Aktualisierung der Kommunikation mit dem Server wird durch AJAX -Technologie erreicht.

Die Anwendung von JavaScript in der realen Welt umfasst Front-End- und Back-End-Entwicklung. 1) Zeigen Sie Front-End-Anwendungen an, indem Sie eine TODO-Listanwendung erstellen, die DOM-Operationen und Ereignisverarbeitung umfasst. 2) Erstellen Sie RESTFUFFUPI über Node.js und express, um Back-End-Anwendungen zu demonstrieren.

Es ist für Entwickler wichtig, zu verstehen, wie die JavaScript -Engine intern funktioniert, da sie effizientere Code schreibt und Leistungs Engpässe und Optimierungsstrategien verstehen kann. 1) Der Workflow der Engine umfasst drei Phasen: Parsen, Kompilieren und Ausführung; 2) Während des Ausführungsprozesses führt die Engine dynamische Optimierung durch, wie z. B. Inline -Cache und versteckte Klassen. 3) Zu Best Practices gehören die Vermeidung globaler Variablen, die Optimierung von Schleifen, die Verwendung von const und lass und die Vermeidung übermäßiger Verwendung von Schließungen.

Python und JavaScript haben ihre eigenen Vor- und Nachteile in Bezug auf Gemeinschaft, Bibliotheken und Ressourcen. 1) Die Python-Community ist freundlich und für Anfänger geeignet, aber die Front-End-Entwicklungsressourcen sind nicht so reich wie JavaScript. 2) Python ist leistungsstark in Bibliotheken für Datenwissenschaft und maschinelles Lernen, während JavaScript in Bibliotheken und Front-End-Entwicklungsbibliotheken und Frameworks besser ist. 3) Beide haben reichhaltige Lernressourcen, aber Python eignet sich zum Beginn der offiziellen Dokumente, während JavaScript mit Mdnwebdocs besser ist. Die Wahl sollte auf Projektbedürfnissen und persönlichen Interessen beruhen.

Sowohl Python als auch JavaScripts Entscheidungen in Entwicklungsumgebungen sind wichtig. 1) Die Entwicklungsumgebung von Python umfasst Pycharm, Jupyternotebook und Anaconda, die für Datenwissenschaft und schnelles Prototyping geeignet sind. 2) Die Entwicklungsumgebung von JavaScript umfasst Node.JS, VSCODE und WebPack, die für die Entwicklung von Front-End- und Back-End-Entwicklung geeignet sind. Durch die Auswahl der richtigen Tools nach den Projektbedürfnissen kann die Entwicklung der Entwicklung und die Erfolgsquote der Projekte verbessert werden.

C und C spielen eine wichtige Rolle in der JavaScript -Engine, die hauptsächlich zur Implementierung von Dolmetschern und JIT -Compilern verwendet wird. 1) C wird verwendet, um JavaScript -Quellcode zu analysieren und einen abstrakten Syntaxbaum zu generieren. 2) C ist für die Generierung und Ausführung von Bytecode verantwortlich. 3) C implementiert den JIT-Compiler, optimiert und kompiliert Hot-Spot-Code zur Laufzeit und verbessert die Ausführungseffizienz von JavaScript erheblich.

JavaScript wird in Websites, mobilen Anwendungen, Desktop-Anwendungen und serverseitigen Programmierungen häufig verwendet. 1) In der Website -Entwicklung betreibt JavaScript DOM zusammen mit HTML und CSS, um dynamische Effekte zu erzielen und Frameworks wie JQuery und React zu unterstützen. 2) Durch reaktnatives und ionisches JavaScript wird ein plattformübergreifendes mobile Anwendungen entwickelt. 3) Mit dem Elektronenframework können JavaScript Desktop -Anwendungen erstellen. 4) Node.js ermöglicht es JavaScript, auf der Serverseite auszuführen und unterstützt hohe gleichzeitige Anforderungen.
