Ein Angular 9 Server Side Rendering Projekt
UPDATE: 10.4.2020, Angular 9
Dieses Tutorial folgt den offiziellen Anweisungen im Universal Guide von Angular und liefert gerenderten Code über das Node.js Express Framework . Wer Nrwl Nx vewendet, sollte diesen Abschnitt überspringen und den Anweisungen unter Nx workspace schematics: server ide rendering (SSR) with Angular Universal folgen.
Erstellen eines Angular-Projekts mit eingebauter SSR Funktionalität
Als Erstes erstellen wir ein neues Angular-Projekt mittels der Angular CLI und fügen ihm einfach Universal Support hinzu.
ng new frontend
cd frontend
ng add @nguniversal/express-engine --clientProject frontend
Der obige Befehl hat unter anderem das Sourcefile
server.ts
auf der obersten Ebene unseres Angular-Projekts hinzugefügt. Dieses File wird der Einstiegspunkt des Node Servers sein, der unsere gerenderten Seiten liefert.
Wir können nun
npm run build:ssr && npm run serve:ssr
ausführen, um das Projekt zu erstellen und unser Angular-Projekt lokal zu testen. Wenn wir nun auf
http://localhost:4200
browsen und den Netzwerkverkehr analysieren, können wir das Resultat bereits sehen:
Die erste Antwort des Servers (nach 20ms) beinhaltet serverseitig gerendertes Html, und das ohne Änderung des Source Codes! Sobald die gebündelten Javascript-Dateien geladen und interpretiert werden, wird das serverseitig gerenderte AppComponent automatisch mit dem, nun im Browser gerenderten Componentcode ersetzt. Dieses Verhalten lässt sich testen, indem ihr in eurem Browser das Javascript deaktiviert .
Ein neues Component hinzufügen
Wir erstellen nun eine, unter
/public/
erreichbar Angular-Route, welche ein Component namens
PublicPageComponent
anzeigt. Dieses Component wird das Einzige sein, welche serverseitig gerendert wird.
PublicPageComponent
gibt den Namen des aktuellen Page-Renderers aus (Browser/Server).
Surft man also auf
/public
, wird zunächst
Rendered by Server
und im nächsten Moment
Rendered by Browser
angezeigt:
Wir erzeugen das Component
cd src
ng g c PublicPage --module app
und fügen zu dieses in
app-routing.module.ts
ein:
const routes: Routes = [{ path: "public", component: PublicPageComponent }];
Schließlich ändern wir den Code der Component, um den aktuellen Renderer anzuzeigen:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
import { Component, Inject, OnInit, PLATFORM_ID } from "@angular/core";
import { isPlatformBrowser } from "@angular/common";
@Component({
selector: "app-public-page",
template: "<p>Rendered by {{ renderer }}</p>",
styleUrls: ["./public-page.component.sass"]
})
export class PublicPageComponent {
renderer: string;
constructor(@Inject(PLATFORM_ID) platformId: any) {
this.renderer = isPlatformBrowser(platformId) ? "Browser" : "Server";
}
}
|
Einrichten eines Nginx-Services, der Requests an den node-js-Server weiterleitet
Um nur einige Teile unserer Website auf der Server-Seite zu rendern, müssen wir mindestens zwei Services laufen haben: Einen Webserver, der sich wie ein Proxy verhält und auf Anfragen des Client-Browsers antwortet und einen anderen, der den Rendering-Prozess bei Bedarf ausführt. Der Einfachheit halber wird der Proxy den gesamten Content bis auf
/public
ausliefern.
Die folgende Grafik bietet einen Überblick der zwei Services:
Deshalb erstellen wir einen Nginx -Service, der die kompilierten Output-Files unserer Angular Website ausliefert.
Wenn wir die folgende Command ausführen
npm run build:ssr
bekommen wir die Output-Files unter:
frontend
+-- dist
+-- browser
... (static files, Angular`s compile output)
+-- server
main.js (Angular SSR bundle)
server.js (-> node.js express engine)
Um den Proxy-Dienst einzurichten, erstellen wir eine
Standard-Nginx-Instanz
und kopieren Dateien von
frontend/dist/browser
in den HTML-Root Ordner (man kann
dieses Dockerfile
verwenden, um einen Container einzurichten).
In unserem Fall ist der Root Ordner
/usr/share/nginx/html
. Daher müssen wir Nginx so konfigurieren, dass es alles aus diesem Ordner heraus bedient, aber
/public
HTTP-Requests an den Angular SSR Node Service weiterleitet.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
server {
listen 80;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html =404;
}
# Forward requests to the node service which
# renders on the server side:
location ~ ^/(public)$ {
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Host $http_host;
proxy_redirect off;
proxy_pass http://internal-hostname-of-ssr-server:4000;
}
include /etc/nginx/extra-conf.d/*.conf;
}
|
Hinweis: Sollen mehrere Seiten serverseitig gerendert werden, so muss Zeile 13 dementsprechend angepasst werden.
Einen NodeJS-Service für SSR einrichten
Schließlich müssen wir noch den Dienst einrichten, der
/public
auf der Serverseite rendert. Nichts könnte einfacher sein - wir haben es schon einmal gemacht:
Durch das Ausführen von
npm run serve:ssr
startet das Service. Aufpassen bei aktivem Output-Filename-Hashing: Node benötigt die
gleichen Output-Dateien
wie das Nginx-Service. Folgendes sollte man daher nicht noch einmal ausführen:
npm run build:ssr
Vollständiges Projektbeispiel mit Docker Containern:
Der obige Code mit allen notwendigen Einstellungen findet sich in folgendem Beispiel-Repository: https://github.com/carrotandcompany/angular-partial-ssr-example .
Glaubt ihr, Server Side Rendering könnte euch bei euren Projekten helfen, und braucht ihr Hilfe beim Aufsetzen?