Serverseitiges Rendern (SSR) ist eine beliebte Technik zum Rendern einer Client-seitigen Einzelseitenanwendung (SPA) auf dem Server und zum anschließenden Senden einer vollständig gerenderten Seite an den Client. Dadurch werden dynamische Komponenten als statisches HTML-Markup bereitgestellt.
Dieser Ansatz kann für die Suchmaschinenoptimierung (SEO) hilfreich sein, wenn die Indizierung JavaScript nicht richtig verarbeitet. Dies kann auch in Situationen von Vorteil sein, in denen das Herunterladen eines großen JavaScript-Bundles durch ein langsames Netzwerk beeinträchtigt wird.
In diesem Tutorial initialisieren Sie eine React-App mit Create React App und ändern das Projekt, um das serverseitige Rendern zu aktivieren.
Am Ende dieses Tutorials haben Sie ein Arbeitsprojekt mit einer Client-seitigen React-Anwendung und einer serverseitigen Express-Anwendung.
Hinweis: Alternativ bietet Next.js einen modernen Ansatz zum Erstellen statischer und vom Server gerenderter Anwendungen, die mit React erstellt wurden.
Um diesem Tutorial zu folgen, benötigen Sie:
Dieses Tutorial wurde mit Node v14.40 und npm
v6.14.5 verifiziert.
Zuerst verwenden wir npx, um eine neue React-Anwendung mit der neuesten Version der Create React App zu starten.
Rufen wir unsere App my-ssr-app auf:
- npx create-react-app@3.4.1 my-ssr-app
Dann nehmen wir cd
in die neue Anweisung auf:
cd my-ssr-app
Schließlich starten wir unsere neue Client-seitige App, um die Installation zu verifizieren:
- npm start
Sie sollten eine Beispiel-React-App-Anzeige in Ihrem Browser-Fenster sehen.
Lassen Sie uns nun eine <Home>
-Komponente erstellen:
- nano src/Home.js
Fügen Sie als Nächstes den folgenden Code in die Datei Home.j
s ein:
import React from 'react';
export default props => {
return <h1>Hello {props.name}!</h1>;
};
Dadurch wird eine <h1>
-Überschrift mit einer "Hello"
-Nachricht erstellt, die an einen Namen geleitet wird.
Als Nächstes rendern wir das <Home>
in der <App>
-Komponente. Öffnen Sie die Datei App.js
:
- nano src/App.js
Ersetzen Sie dann die vorhandenen Codezeilen durch diese neuen Codezeilen:
import React from 'react';
import Home from './Home';
export default () => {
return <Home name="Sammy" />;
};
Dadurch wird ein Name
an die <Home>
-Komponente übergeben, sodass die Nachricht, die wir erwarten, "Hello Sammy!"
lautet.
In der Datei index.js
unserer App verwenden wir die ReactDOM-Hydratmethode
anstelle des Renderns
, um dem DOM-Renderer anzuzeigen, dass wir die App nach einem serverseitigen Rendern rehydrieren.
Öffnen wir die Datei index.js
:
- nano index.js
Ersetzen Sie dann den Inhalt der Datei index.js
durch den folgenden Code:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
ReactDOM.hydrate(<App />, document.getElementById('root'));
Damit wird die Einrichtung der Client-Seite abgeschlossen, wir können mit der Einrichtung der Server-Seite fortfahren.
Nachdem wir nun unsere Anwendung eingerichtet haben, richten wir einen Server ein, der eine gerenderte Version übergeben wird. Wir verwenden Express für unseren Server. Fügen wir es dem Projekt hinzu, indem wir den folgenden Befehl in Ihrem Terminalfenster eingeben:
- npm install express@4.17.1
Oder mit yarn:
- yarn add express@4.17.1
Erstellen Sie als Nächstes ein Server
-Verzeichnis neben dem Verzeichnis src
der App:
- mkdir server
Erstellen Sie dann eine neue Datei index.js
, die den Express-Servercode enthält:
- nano server/index.js
Fügen Sie die Importe hinzu, die einige Konstanten benötigen, und definieren Sie diese auch:
import path from 'path';
import fs from 'fs';
import React from 'react';
import express from 'express';
import ReactDOMServer from 'react-dom/server';
import App from '../src/App';
const PORT = process.env.PORT || 3006;
const app = express();
Fügen Sie als Nächstes den Servercode mit einer Fehlerbehandlung hinzu:
// ...
app.get('/', (req, res) => {
const app = ReactDOMServer.renderToString(<App />);
const indexFile = path.resolve('./build/index.html');
fs.readFile(indexFile, 'utf8', (err, data) => {
if (err) {
console.error('Something went wrong:', err);
return res.status(500).send('Oops, better luck next time!');
}
return res.send(
data.replace('<div id="root"></div>', `<div id="root">${app}</div>`)
);
});
});
app.use(express.static('./build'));
app.listen(PORT, () => {
console.log(`Server is listening on port ${PORT}`);
});
Wie Sie möglicherweise sehen, können wir unsere <App>
-Komponente aus der Client-App direkt vom Server importieren.
Hier finden drei wichtige Dinge statt:
build
als statische Dateien zu verwenden.ReactDOMServer
, renderToString
, um unsere App zu einer statischen HTML-Zeichenfolge zu rendern.index.html
aus der integrierten Client-App, injizieren den statischen Inhalt unserer App im <div>
mit einer ID
von "root"
, und senden dies als Antwort auf die Anfrage.npm
ScriptsDamit unser Servercode funktioniert, müssen wir ihn mit webpack und Babel bündeln und transpilieren. Dazu fügen wir dem Projekt die Abhängigkeiten dev hinzu, indem wir den folgenden Befehl in Ihrem Terminalfenster eingeben:
- npm install webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --save-dev
Oder mit yarn:
- yarn add webpack@4.42.0 webpack-cli@3.3.12 webpack-node-externals@1.7.2 @babel/core@7.10.4 babel-loader@8.1.0 @babel/preset-env@7.10.4 @babel/preset-react@7.10.4 --dev
Hinweis: Eine frühere Version dieses Tutorials installierte babel-core
, babel-preset-env
und babel-preset-react-app
. Diese Pakete wurden seitdem archiviert, und die mono-repo-Versionen werden stattdessen verwendet.
Erstellen Sie als Nächstes eine Babel-Konfigurationsdatei:
- nano .babelrc.json
Fügen Sie dann die Voreinstellungen env
und react-app
hinzu:
{
"presets": [
"@babel/preset-env",
"@babel/preset-react"
]
}
Anmerkung: Eine frühere Version dieses Tutorials verwendete eine .babelrc
-Datei (keine .json
-Dateierweiterung). Dies war eine Konfigurationsdatei für Babel 6, aber dies ist für Babel 7 nicht mehr der Fall.
Jetzt erstellen wir eine webpack-Konfiguration für den Server, der Babel Loader verwendet, um den Code zu transpilieren. Beginnen Sie mit der Erstellung der Datei:
- nano webpack.server.js
Fügen Sie dann die folgenden Konfigurationen in die webpack.server.js
-Datei ein:
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: './server/index.js',
target: 'node',
externals: [nodeExternals()],
output: {
path: path.resolve('server-build'),
filename: 'index.js'
},
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader'
}
]
}
};
Mit dieser Konfiguration wird unser transpiliertes Serverbundle an den Ordner server-build
in einer Datei namens index.js
ausgegeben.
Beachten Sie die Verwendung von target: 'node'
und externals: [nodeExternals()]
aus webpack-node-externals
, wodurch die Dateien aus node_modules
im Bundle versagt werden; der Server kann direkt auf diese Dateien zugreifen.
Dadurch wird die Abhängigkeit von der Installation und der webpack- und Babel-Konfiguration abgeschlossen.
Jetzt besuchen wir erneut package.json
, um Helfer-npm
-Scripts hinzuzufügen:
- nano package.json
Wir fügen der Datei package.json
die Scripts dev:build-server
, dev:start
und dev
hinzu, um unsere SSR-Anwendung leicht zu erstellen und zu bedienen:
"scripts": {
"dev:build-server": "NODE_ENV=development webpack --config webpack.server.js --mode=development -w",
"dev:start": "nodemon ./server-build/index.js",
"dev": "npm-run-all --parallel build dev:*",
...
},
Wir verwenden nodemon
, um den Server neu zu starten, wenn wir Änderungen daran durchführen. Und wir verwenden npm-run-all
, um mehrere Befehle parallel auszuführen.
Installieren wir diese Pakete nun durch Eingabe der folgenden Befehle in Ihrem Terminalfenster
- npm install nodemon@2.0.4 npm-run-all@4.1.5 --save-dev
Oder mit yarn:
- yarn add nodemon@2.0.4 npm-run-all@4.1.5 --dev
Damit können Sie Folgendes ausführen, um die Client-seitige App zu erstellen, den Servercode zu bündeln und zu transpilieren, und den Server unter :3006
zu starten:
- npm run dev
Oder mit yarn:
- yarn run dev
Unsere Server-Webpack-Konfiguration wir auf Änderungen achten und unser Server wird bei Änderungen neu starten. Für die Client-Anwendung müssen wir sie jedoch derzeit immer noch jedes Mal erstellen, wenn wir Änderungen vornehmen. Dafür gibt es hier ein offenes Problem.
Öffnen Sie nun http://localhost:3006/
in Ihrem Webbrowser und Sie sehen Ihre App auf der Serverseite gerendered.
Zuvor hat der Quellcode enthüllt:
Output<div id="root"></div>
Mit den Änderungen, die Sie vorgenommen haben, enthüllt der Quellcode nun aber:
Output<div id="root"><h1 data-reactroot="">Hello <!-- -->Sammy<!-- -->!</h1></div>
Das serverseitige Rendering hat die <App>
-Komponente erfolgreich in HTML konvertiert.
In diesem Tutorial haben Sie eine React-Anwendung initialisiert und das serverseitige Rendering aktiviert.
In diesem Beitrag haben wir erst einen Bruchteil des Möglichen besprochen. Die Dinge werden etwas komplizierter, wenn Routing, Datenabruf oder Redux ebenfalls Teil einer serverseitig gerenderten App sein müssen.
Ein Hauptvorteil der Verwendung von SSR besteht darin, dass eine App für ihren Inhalt gecrawlt werden kann, selbst für Crawler, die keinen JavaScript-Code ausführen. Dies kann bei der Suchmaschinenoptimierung (SEO) und der Bereitstellung von Metadaten für Social-Media-Kanäle hilfreich sein.
SSR kann auch häufig zur Leistungssteigerung beitragen, da bei der ersten Anforderung eine vollständig geladene App vom Server gesendet wird. Bei nicht trivialen Apps kann Ihr Kilometerstand variieren, da für SSR ein Setup erforderlich ist, das etwas kompliziert werden kann und den Server stärker belastet. Ob Sie serverseitiges Rendering für Ihre React-App verwenden, hängt von Ihren spezifischen Anforderungen ab und davon, welche Kompromisse für Ihren Anwendungsfall am sinnvollsten sind.
Wenn Sie mehr über React erfahren möchten, sehen Sie sich unsere Reihe Codieren in React.js an oder besuchen Sie unsere React-Themenseite für Übungen und Programmierprojekte.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!