NestJs Vercel Hosting

Erfahrungen aus der Praxis: NestJS auf Vercel hosten

Nachdem ich Stunden damit verbracht habe, meine NestJS-App auf Vercel zu hosten und es nicht zum Laufen brachte, dachte ich mir, dass es an der Zeit ist, zu dokumentieren, was ich gelernt habe – nicht nur, um mir in Zukunft Zeit zu sparen, sondern hoffentlich auch, um anderen zu helfen, einige der Fallstricke zu vermeiden, in die ich geraten bin. Hier ist eine Aufschlüsselung dessen, was funktioniert hat, was nicht, und wie ich es schließlich geschafft habe, dass alles reibungslos läuft.

Das könnte dich ebenfalls interessieren: Swagger zu Node Server hinzufügen

Schritt 1: NestJS auf Vercel hosten

Das Wichtigste zuerst: Die Grundeinstellungen für die Bereitstellung auf Vercel. Vercel ist großartig für Serverless, aber die Arbeit mit NestJS benötigt ein paar Anpassungen. Die Hauptsache ist, eine vercel.json-Konfigurationsdatei einzurichten, die Vercel genau sagt, wie die App zu behandeln ist.

Hier ist die Endkonfiguration:

{
  "version": 2,
  "builds": [
    {
      "src": "src/main.ts",
      "use": "@vercel/node"
    }
  ],
  "routes": [
    {
      "src": "/(.*)",
      "dest": "src/main.ts",
      "methods": [
        "GET",
        "POST",
        "PUT",
        "PATCH",
        "OPTIONS",
        "DELETE",
        "HEAD",
        "CONNECT",
        "TRACE"
      ]
    }
  ]
}

Ich habe daraufhin in Vercel folgende Fehlermeldung erhalten:

This Serverless Function has crashed. Your connection is working correctly. 
Vercel is working correctly. 500: INTERNAL_SERVER_ERROR 
Code: FUNCTION_INVOCATION_FAILED ID: bom1::sgk4v-1711014022883-1e9ed54f4c37

Bei einem Blick in die Logs stellte ich fest, dass die Datenbankverbindung ein Problem darstellte und außerdem die folgende Logmeldung angezeigt wurde:

No exports found in module "/var/task/app-name/src/main.js".
Did you forget to export a function or a server?

Es stellte sich heraus, dass ich den zweiten Teil der Fehlermeldung ignorieren und mich nur auf die Datenbankverbindung konzentrieren musste.

Schritt 2: Konfigurieren der Datenbank

Für meine Anwendung habe ich eine mysql-Datenbank mit mehreren Schemata verwendet. Ich habe mehrere kostenlose Angebote ausprobiert, aber sie waren nicht mit dem Ansatz mehrerer Schemata kompatibel. Daher habe ich mich für das Hosting bei Google Cloud entschieden. Ich habe es auf einen Preis von 0,01 $ pro Stunde heruntergeschraubt und das 300 $-Einsteigerangebot genutzt.

Um Vercel eine Verbindung zu ermöglichen, musste in der Konfiguration von Google Cloud die IP-Adresse auf 0.0.0.0/0 gesetzt werden, so dass die Datenbank von jeder IP-Adresse aus zugänglich war.

Schritt 3: Umgang mit CORS

Die CORS Fehler haben auch für einige Kopfschmerzen gesorgt. Stelle sicher, dass OPTIONS für CORS Preflight-Anfragen zugelassen wird, da Vercel eine explizite Erlaubnis für Cross-Origin-Anfragen benötigt. Am Ende musste ich eine Menge Header hinzufügen, um sicherzustellen, dass die Anfragen erlaubt waren:

app.enableCors({
    origin: 'domain-name',
    credentials: true,
    methods: 'GET,HEAD,PUT,PATCH,POST,DELETE,OPTIONS',
    allowedHeaders: [
      'Origin',
      'X-Requested-With',
      'Content-Type',
      'Accept',
      'Authorization',
    ],
  });

Schritt 4: Umstellung auf express-session und Redis für die Sitzungsverwaltung

Einer der kniffligsten Teile war die Sessions zum Laufen zu bringen. Ich begann mit der cookie-session Bibliothek, aber Vercel ignoriert sie komplett. Nach einem Blick in die Dokumentation und einigem Ausprobieren wechselte ich zur express-session Bibliothek, da sie populärer ist und besser mit Vercels serverloser Umgebung funktioniert.

Aus irgendeinem Grund muss die Import-Syntax genau so aussehen:

import session = require('express-session');

Außerdem musste ich die Sitzungsmiddleware mit aktiviertem Vertrauensproxy konfigurieren, da Vercel Anfragen proxifiziert. So sieht die Einstellung aus:

const expressApp = app.getHttpAdapter().getInstance();
expressApp.set('trust proxy', true);

Auch die Einstellung secure: true und sameSite: ’none‘ war wichtig, um sicherzustellen, dass Cookies über HTTPS und verschiedene Domainanfragen funktionieren!

Beachten, dass mit Vercel mehrere serverlose Instanzen Anfragen bearbeiten können, was bei parallelen Anfragen leider zu Sitzungskonflikten führt. Um dies zu beheben, habe ich meinen Sitzungsspeicher mit einer Redis-Instanz verbunden. Glücklicherweise war das super einfach.

Redis hält die Sitzungsdaten konsistent und vermeidet Konflikte zwischen Anfragen, insbesondere unter Last. Hier der Code:

const expressApp = app.getHttpAdapter().getInstance();
expressApp.set('trust proxy', true);

const redisClient = createClient({
    password: process.env.REDIS_PASSWORD,
    socket: {
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT, 10),
    },
  });

  redisClient
    .connect()
    .catch((err) =>
      console.log('Could not establish a connection with Redis: ' + err),
    );

  redisClient.on('error', (err) => console.log('Redis error: ' + err));
  redisClient.on('connect', () =>
    console.log('Connected to Redis successfully'),
  );

  app.use(
    session({
      store: new RedisStore({ client: redisClient }),
      secret: process.env.COOKIE_SECRET,
      cookie: {
        secure: process.env.NODE_ENV !== 'development',
        sameSite: process.env.NODE_ENV === 'development' ? 'lax' : 'none',
        maxAge: 86400000,
      },
    }),
  );

Schritt 5: Hinzufügen von withCredentials im Frontend

Dieser Schritt ist nur eine Randnotiz: Damit Session-Cookies zwischen Frontend und Backend funktionieren, muss withCredentials in den HTTP-Anfragen meines Frontends auf true gesetzt werden. Dies ermöglicht die Einbeziehung von Cookies in herkunftsübergreifende Anfragen, was wichtig ist, wenn das Frontend und das Backend getrennt gehostet werden. Ich musste sicherstellen, dass der HTTP-Client von Angular diese Einstellung aktiviert hat.

Schritt 6: Schriftart hinzufügen

Um Schriftdateien in Ihr NestJS-Projekt einzubinden, muss man die CompilerOptions in der nest-cli.json-Datei verwenden, um Assets für die Build-Ausgabe zu definieren, z. B. durch die Angabe von „include“: „**/*.ttf“ und ‚outDir‘: „dist/src“.

{
  "$schema": "https://json.schemastore.org/nest-cli",
  "collection": "@nestjs/schematics",
  "sourceRoot": "src",
  "compilerOptions": {
    "assets": [
      {
        "include": "**/*.ttf",
        "outDir": "dist/src"
      }
    ],
    "deleteOutDir": true
  }
}

Anschließend kann man nach dem Build die Schriftarten im Code mit path.resolve referenzieren, z. B. path.resolve(__dirname, ‚../fonts/Roboto-Regular.ttf‘). Auf diese Weise wird sichergestellt, dass die Schriftartendateien mit dem Build gebündelt werden und während der Laufzeit zugänglich sind.

Schlussgedanken zum Thema NestJS auf Vercel hosten

Das Deployment meiner NestJS-App auf Vercel war eine wahre Achterbahnfahrt. Manchmal hatte ich das Gefühl, dass ich kurz davor war, alles perfekt zum Laufen zu bringen, nur um dann mit neuen Fehlern konfrontiert zu werden, die mich zurück in den Fehlersuch-Modus schickten. Es gab Momente der Frustration – vor allem im Zusammenhang mit der Sessionverarbeitung und CORS-Problemen. Aber jede Lösung brachte ein neues Hoch, und jeder behobene Fehler fühlte sich wie ein kleiner Sieg an.

Jetzt, wo endlich alles reibungslos funktioniert, kann ich sagen, dass es ein großartiges Gefühl ist. Wenn ich sehe, dass meine Anwendung so funktioniert, wie ich es mir vorgestellt habe, ist das all die Kopfschmerzen wert. Es ist eine große Erleichterung, aber noch mehr freut es mich, zu wissen, dass ich jede Hürde überwunden habe und auf das, was ich gelernt habe, zurückblicken kann. Ich hoffe, dieser Leitfaden kann anderen einige dieser Schwierigkeiten ersparen und helfen, diesen „Es funktioniert einfach“-Moment etwas schneller zu erreichen!

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Cookie Consent mit Real Cookie Banner