Die Bereitstellung einer React-App auf Microsoft Azure ist einfach. Außer, dass... sie es nicht ist. Der Teufel steckt im Detail. Wenn Sie eine create-react-app – oder ein ähnliches Frontend-JavaScript-Framework, das pushState-basiertes Routing erfordert – auf Microsoft Azure bereitstellen möchten, glaube ich, dass dieser Artikel Ihnen gute Dienste leisten wird. Wir werden versuchen, die Kopfschmerzen der Client- und Serverseiten-Routing-Abgleichung zu vermeiden.
Zuerst eine kurze Geschichte.
Im Jahr 2016, als Donovan Brown, ein Senior DevOps Program Manager bei Microsoft, auf der Microsoft Connect in diesem Jahr eine Rede hielt, die als „aber es funktioniert auf meinem Rechner“ bekannt wurde, war ich als Webentwickler noch in meinen Anfängen. Sein Vortrag handelte von Microservices und Containern.
[…] Vorbei sind die Tage, an denen Ihr Manager panisch in Ihr Büro rennt und einen Fehler gefunden hat. Und egal wie sehr ich mich anstrenge, ich kann ihn nicht reproduzieren und er funktioniert perfekt auf meinem Rechner. Sie sagt: In Ordnung, Donovan, dann werden wir deinen Rechner ausliefern, denn das ist der einzige Ort, an dem er funktioniert. Aber ich mag meinen Rechner, also lasse ich sie ihn nicht ausliefern...
Ich hatte eine ähnliche Herausforderung, die sich jedoch auf das Routing bezog. Ich arbeitete an einer Website mit einem React-Frontend und einem ASP.NET Core-Backend, die als zwei separate Projekte gehostet und auf Microsoft Azure bereitgestellt wurden. Das bedeutete, dass wir beide Apps separat bereitstellen und die Vorteile der Trennung von Belangen genießen konnten. Wir wussten auch, wer im Falle eines Problems zu git blame war. Aber es gab auch Nachteile, da die Abgleichung von Frontend- und Backend-Routing einer dieser Nachteile war.
Eines Tages lud ich neuen Code auf unsere Staging-Server hoch. Kurz darauf erhielt ich eine Nachricht, dass die Website beim Aktualisieren der Seite fehlschlagte. Es wurde ein 404-Fehler ausgegeben. Zuerst dachte ich nicht, dass es meine Verantwortung sei, den Fehler zu beheben. Es musste ein Problem mit der Serverkonfiguration sein. Es stellte sich heraus, dass ich sowohl richtig als auch falsch lag.
Ich lag richtig in dem Wissen, dass es sich um ein Problem mit der Serverkonfiguration handelte (obwohl ich zu diesem Zeitpunkt nicht wusste, dass es mit dem Routing zu tun hatte). Ich lag falsch, als ich es von meiner Verantwortung ablehnte. Erst nachdem ich mich auf eine wilde Websuche begeben hatte, fand ich einen Anwendungsfall für die Bereitstellung einer create-react-app auf Azure unter dem Reiter „Deployment“ auf der offiziellen Dokumentationsseite.
React für die Produktion erstellen
Wenn Sie eine React-App für die Produktion erstellen (vorausgesetzt, wir verwenden create-react-app), lohnt es sich, die generierten Ordner zu beachten. Wenn Sie npm run build ausführen, wird ein Build-Ordner generiert, in dem eine optimierte statische Version der Anwendung gespeichert ist. Um die Anwendung auf einem Live-Server zu erhalten, müssen wir lediglich den Inhalt des Build-Ordners an den Server übergeben. Wenn wir auf localhost arbeiteten, war kein *Live-Server* beteiligt, daher ist dies nicht immer gleichbedeutend mit der Bereitstellung der Anwendung auf einem Live-Server.
Im Allgemeinen hat der Build-Ordner diese Struktur
→ build
→ static
→ css
→ css files
→ js
→ js files
→ media
→ media files
→ index.html
→ other files...
Clientseitiges Routing mit React Router
React Router verwendet intern die HTML5 pushState History API. Was pushState tut, ist ziemlich interessant. Zum Beispiel, wenn Sie von der Seite https://css-tricks.de zur Seite https://css-tricks.de/archives/ navigieren (oder Link in React Router verwenden), wird die URL-Leiste https://css-tricks.de/archives/ anzeigen, aber der Browser wird nicht die Seite /archives laden oder sogar prüfen, ob sie existiert. Kombiniert mit dem komponenten-basierten Modell von React wird es zu einer Sache, Routen zu ändern, während verschiedene Seiten basierend auf diesen Routen angezeigt werden – ohne das allsehende Auge des Servers, das versucht, eine Seite in seinem eigenen Verzeichnis bereitzustellen. Was passiert dann, wenn wir Server einführen, indem wir den Code auf einen *Live-Server* pushen? Die Dokumentation erklärt es besser
Wenn Sie Router verwenden, die intern die HTML5 pushState History API nutzen (z. B. React Router mit browserHistory), werden viele statische Dateiserver fehlschlagen. Wenn Sie beispielsweise React Router mit einer Route für /todos/42 verwenden, antwortet der Entwicklungsserver auf localhost:3000/todos/42 ordnungsgemäß, aber ein Express, das einen Produktions-Build wie oben bedient, wird dies nicht tun. Das liegt daran, dass bei einem neuen Seitenaufruf für /todos/42 der Server nach der Datei build/todos/42 sucht und sie nicht findet. Der Server muss so konfiguriert werden, dass er auf eine Anfrage an /todos/42 antwortet, indem er index.html bereitstellt.
Verschiedene Server erfordern unterschiedliche Konfigurationen. Express zum Beispiel benötigt dies
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
...wie in der create-react-app Dokumentation beschrieben. **Beachten Sie jedoch, dass dies davon ausgeht, dass wir create-react-app im Server-Root hosten**, was eine Wildcard-Route (*) verwendet, die alle Routen abfängt und auf alle Routenanfragen mit der Bereitstellung der Datei index.html im Build-Ordner antwortet, der sich im Stammverzeichnis der Serveranwendung befindet. Außerdem ist dies eng mit dem Backend gekoppelt. Wenn das der Fall ist, würden wir höchstwahrscheinlich diese Art von Ordnerstruktur haben (angenommen, das Backend ist in NodeJS)
→ Server
→ Client (this is where your react code goes)
→ build (this is the build folder, after you npm run build)
→ src
→ node_modules
→ package.json
→ other front-end files and folders
→ Other back-end files and folders
Da mein Frontend (create-react-app) und mein Backend (ASP.NET) zwei verschiedene Projekte waren, war die Bereitstellung statischer Dateien durch Navigation im Verzeichnis eine Art *Unmöglichkeit*.
Tatsächlich brauchen wir das Backend nicht, da wir eine statische App bereitstellen. Wie Burke Holland es ausdrückte: „Statisch“ bedeutet, dass wir keinen Server-Code bereitstellen; nur die Frontend-Dateien.
Ich erwähne hier immer wieder ASP.NET, da ich bei meinen Recherchen festgestellt habe, dass für die Konfiguration von Azure eine Konfigurationsdatei in einem
wwwroot-Ordner erforderlich ist und die Ordnerstruktur von ASP.NET typischerweise einenwwwroot-Ordner hat. Erinnern Sie sich, das Backend der Anwendung war in ASP.NET? Aber das ist auch schon alles. Derwwwroot-Ordner schien irgendwo auf Azure versteckt zu sein. Und ich kann ihn nicht zeigen, ohne einecreate-react-appbereitzustellen. Lassen Sie uns das also tun.
Erste Schritte mit App Services auf Microsoft Azure
Um zu beginnen, wenn Sie noch kein Azure-Konto haben, holen Sie sich eine kostenlose Testversion und gehen Sie dann zum Azure-Portal.
- Navigieren Sie zu Alle Dienste → Web → App Services
Navigation im Azure-Portal von Alle Dienste zu Web zu App Services
- Wir möchten eine neue App hinzufügen, ihr einen Namen, ein Abonnement (sollte kostenlos sein, wenn Sie eine kostenlose Testversion haben oder bereits eine besitzen), eine Ressourcengruppe (eine erstellen oder eine vorhandene verwenden) geben und dann unten im Fenster auf die Schaltfläche „Erstellen“ klicken.

Erstellung eines neuen App Service im Azure-Portal. - Wir sollten eine Benachrichtigung erhalten, dass die Ressource erstellt wurde. Sie wird jedoch nicht sofort angezeigt. Klicken Sie daher auf „Aktualisieren“ – ich habe andere Ressourcen, aber AzureReactDemo2 ist das, was ich hier verwende. Sie klicken auf den Namen Ihrer neu erstellten App, die in meinem Fall AzureReactDemo2 ist.

Anzeige aller App Services im Azure-Portal. - Das Fenster zeigt Ihnen Informationen über Ihre App. Die Navigation auf der linken Seite enthält alles, was Sie zur Verwaltung Ihrer Anwendung benötigen (Übersicht, Aktivitätsprotokoll, Bereitstellungszentrum...).
Zum Beispiel ist das Bereitstellungszentrum der Ort, an dem die Anwendungsbereitstellung verwaltet wird, Slots ist, wo Dinge wie Staging, Produktion, Test verwaltet werden. Die Konfiguration ist der Ort, an dem Umgebungsvariablen, Node-Versionen und – ein wichtiger Punkt – Kudu verwaltet werden.
Der Übersichts-Bildschirm zeigt eine allgemeine Ansicht des Anwendungsstatus, der URL… Klicken Sie auf die URL, um die Live-Site zu sehen.

Die App läuft!

Wir haben einen neuen App Service erstellt, aber wir haben noch keinen unserer Codes auf Azure. Wie bereits erwähnt, müssen wir Azure nur den Inhalt des Build-Ordners zuführen, der durch das Erstellen von React für die Produktion generiert wird, aber wir haben noch keinen. Lassen Sie uns also lokal gehen und uns eine React-App besorgen.
Lokal gehen
Wir müssen eine neue React-App erstellen und react-router als Abhängigkeit installieren.
npx create-react-app azure-react-demo
cd azure-react-demo
Wir wollen auch react-router (eigentlich react-router-dom) installieren
npm i react-router-dom
Wenn alles gleich ist und wir die App mit npm start starten, sollten wir die Standardseite erhalten.

Da es hier um das Testen von Routen geht, musste ich einige Seiten erstellen. Ich habe meine lokale Version geändert und sie auf GitHub hochgeladen. Ich gehe davon aus, dass Sie sich mit React und React-Router auskennen. Demo herunterladen.
Mein Ordner sieht so aus

Die geänderten Dateien enthalten folgenden Code
// App.js
import React, { Component } from "react";
import "./App.css";
import Home from "./pages/Home";
import Page1 from "./pages/Page1";
import Page2 from "./pages/Page2";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
class App extends Component {
render() {
return (
<Router>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/page1" component={Page1} />
<Route path="/page2" component={Page2} />
</Switch>
</Router>
);
}
}
export default App;
// Page1.js
import React from "react";
import { Link } from "react-router-dom";
const Page1 = () => {
return (
<div className="page page1">
<div className="flagTop" />
<div className="flagCenter">
<h1 className="country">Argentina (PAGE 1)</h1>
<div className="otherLinks">
<Link to="/page2">Nigeria</Link>
<Link to="/">Home</Link>
</div>
</div>
<div className="flagBottom" />
</div>
);
};
export default Page1;
// Page2.js
import React from "react";
import { Link } from "react-router-dom";
const Page2 = () => {
return (
<div className="page page2">
<div className="flagTop" />
<div className="flagCenter">
<h1 className="country">Nigeria (PAGE 2)</h1>
<div className="otherLinks">
<Link to="/page1">Argentina</Link>
<Link to="/">Home</Link>
</div>
</div>
<div className="flagBottom" />
</div>
);
};
export default Page2;
/* App.css */
html {
box-sizing: border-box;
}
body {
margin: 0;
}
.page {
display: grid;
grid-template-rows: repeat(3, 1fr);
height: 100vh;
}
.page1 .flagTop,
.page1 .flagBottom {
background-color: blue;
}
.page2 .flagTop,
.page2 .flagBottom {
background-color: green;
}
.flagCenter {
display: flex;
align-items: center;
flex-direction: column;
justify-content: center;
text-align: center;
}
.page a {
border: 2px solid currentColor;
font-weight: bold;
margin: 0 30px;
padding: 5px;
text-decoration: none;
text-transform: uppercase;
}
.flags {
display: flex;
width: 100%;
}
.flags > .page {
flex: 1;
}
Die App funktioniert lokal, sodass die Routen geliefert werden, wenn auf Links geklickt wird und sogar, wenn die Seite aktualisiert wird.
App auf Azure bereitstellen
Jetzt bringen wir sie auf Azure! Dafür sind ein paar Schritte nötig.
Schritt 1: Zum Bereitstellungszentrum gehen
Auf Azure müssen wir zum Bereitstellungszentrum gehen. Es gibt einige Optionen, jede mit ihren Vor- und Nachteilen. Wir werden Local Git verwenden (was bedeutet, dass Ihre lokale Git-App direkt nach Azure geht) für die Quellcodeverwaltung und Kudu für den Build-Provider.
Denken Sie daran, auf Weiter oder Fertig zu klicken, nachdem Sie eine Option ausgewählt haben, sonst starrt das Portal Sie nur an.



Nach dem dritten Schritt generiert Azure ein lokales Git-Repository für Sie. Und es gibt Ihnen einen Remote-Link, auf den Sie Ihre React-App verweisen können.
Eine Sache, die man zu diesem Zeitpunkt beachten sollte. Wenn Sie pushen, wird Azure nach Ihren GitHub-Anmeldedaten fragen. Sie befinden sich unter dem Reiter „Bereitstellung“. Es gibt zwei: App und Benutzer. App-Anmeldedaten sind speziell für eine App. Benutzer sind allgemein für alle Apps, auf die Sie als Benutzer Lese-/Schreibzugriff haben. Sie können ohne Benutzer-Anmeldedaten auskommen und App-Anmeldedaten verwenden, aber ich habe festgestellt, dass Azure nach einer Weile aufhört, nach Anmeldedaten zu fragen, und mir automatisch mitteilt, dass die Authentifizierung fehlgeschlagen ist. Ich habe benutzerdefinierte Benutzer-Anmeldedaten festgelegt. So oder so sollten Sie das überstehen.

In der React-App müssen wir nach der Änderung für die Produktion bauen. Das ist wichtig, denn was wir hochladen wollen, ist der Inhalt des Build-Ordners.
Wir müssen Kudu mitteilen, welche Node-Engine wir verwenden werden, sonst wird der Build wahrscheinlich fehlschlagen,
aufgrund der Tatsache, dass react-scripts eine Node-Version höher als die auf Azure standardmäßig eingestellte benötigt. Es gibt andere Möglichkeiten, dies zu tun, aber die einfachste ist, eine Node-Engine in package.json hinzuzufügen. Ich verwende hier Version 10.0. Leider können wir nicht einfach hinzufügen, was wir wollen, da Azure unterstützte Node-Versionen hat und der Rest nicht unterstützt wird. Prüfen Sie das mit der CLI mit dem Befehl: az webapp list-runtimes
Fügen Sie die bevorzugte Node-Version zur Datei package.json hinzu, wie in
"engines": {
"node": "10.0"
}

Schritt 2: Die App bauen
Um die React-App zu bauen, führen wir npm build im Terminal aus.
Schritt 3: Das Git-Repository initialisieren
Navigieren Sie in den Build-Ordner und initialisieren Sie dort ein Git-Repository. Die URL zum Klonen des Repos ist auf der Übersichtsseite. Abhängig von den verwendeten Anmeldedaten (App oder Benutzer) wird sie leicht unterschiedlich sein.

git init
git add .
git commit -m "Initial Commit"
git remote add azure <git clone url>
git push azure master
Besuchen Sie nun die Live-App über die URL auf der Übersichtsseite. Wie Sie sehen können, schlägt die App bei der Aktualisierung von /page2 fehl. Ein Blick in den Netzwerk-Tab zeigt einen 404-Fehler, da die Seite vom Server abgerufen werden sollte – mit clientseitigem Routing, wie wir es bereits eingerichtet haben, sollte die Seite gar nicht vom Server abgerufen werden.

Azure konfigurieren, um Client- und Serverseiten-Routing abzugleichen
Fügen wir im öffentlichen Ordner eine web.config XML-Datei mit folgendem Inhalt hinzu
<?xml version="1.0"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="React Routes" stopProcessing="true">
<match url=".*" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />
</conditions>
<action type="Rewrite" url="/" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Ich habe mich absichtlich entschieden, das Code-Snippet nicht zu formatieren, da XML hier streng ist. Wenn Sie die Formatierung verpassen, hat die Datei keine Wirkung. Sie können einen XML-Formatter für Ihren Texteditor herunterladen. Für VSCode wäre das das XML Tools Plugin.

Die App kann zu diesem Zeitpunkt erneut gebaut werden, obwohl wir die Git-Informationen im Build-Ordner verlieren werden, da der neue Build den alten überschreibt. Das bedeutet, dass sie erneut hinzugefügt und dann gepusht werden müsste.
Jetzt funktioniert die App wie unten gezeigt! Puh.
Wir wollen nicht jedes Mal npm run build ausführen – dafür gibt es Continuous Deployment. Schauen Sie sich den folgenden Link für passende Referenzen an.
Fazit
Es gibt viel über Azure zu sagen, da es viel für Sie tun kann. Das ist gut so, denn es gibt Zeiten, in denen Sie möchten, dass es etwas Bestimmtes tut – wie hier beim Abgleichen von Client- und Serverseiten-Routing – und es hat Sie bereits abgesichert.
Damit verlasse ich Sie mit ein paar verwandten Ressourcen, auf die Sie zurückgreifen können, wenn Sie eine React-App auf Azure bereitstellen möchten.
- Benutzerdefinierte NodeJs-Bereitstellung auf Azure Web App von Hao Luo: Erfahren Sie mehr über Kudu und NodeJS-Bereitstellung.
- Bereitstellung einer React-App als statische Website auf Azure von Burke Holland: Noch mehr Optionen für die Bereitstellung von create-react-app auf Microsoft Azure.
Gut gemacht, aber könnten Sie erklären, was diese Zeile in der web.config-Datei tut?
<add input="{REQUEST_URI}" pattern="^/(api)" negate="true" />Sie möchten alle URLs abgleichen und sie dann zur
index-Datei umleiten.Sie verwenden
<match url=".*" />(gleiche alle URLs ab) und führen eine „Rewrite-Aktion“ zur Index-Datei mit<action type="Rewrite" url="/" />durch.Die
<conditions>...</conditions>gelten nicht für den Zugriff auf Dateien und Verzeichnisse oder wenn die URI das Muster^/(api)aufweist.Sie könnten damit noch weiter gehen, je nachdem, wie tief Sie KUDU verstehen.
Lesen Sie hier, um ein tiefgehendes Wissen über KUDU zu erhalten: https://github.com/projectkudu/kudu/wiki