Freigeben über


Orchestrieren von Node.js-Apps in .NET Aspire

In diesem Artikel erfahren Sie, wie Sie Node.js- und Node Package Manager -Apps (npm) in einem .NET.NET Aspire Projekt verwenden. Die Beispiel-App in diesem Artikel veranschaulicht Angular, Reactund Vue Clienterfahrungen. Die folgenden .NET.NET Aspire-APIs sind vorhanden, um diese Szenarien zu unterstützen, die Teil des Aspire.Hosting.NodeJS NuGet-Pakets sind.

Der Unterschied zwischen diesen beiden APIs besteht darin, dass die erste zum Hosten von Node.js Apps verwendet wird, während die letztere zum Hosten von Apps verwendet wird, die aus dem scripts-Abschnitt einer package.json-Datei ausgeführt werden—und dem entsprechenden npm run <script-name>-Befehl.

Trinkgeld

Der Beispielquellcode für diesen Artikel ist auf GitHubverfügbar, und es gibt Details auf der Seite zu den Codebeispielen: .NET Aspire mit Angular, React und Vue.

Wichtig

Während sich dieser Artikel auf Single-Page App-Frontend-Bits (SPA) konzentriert, gibt es auf den Codebeispiele ein zusätzliches Node.js Beispiel verfügbar: .NET AspireNode.js Beispiel Seite, die veranschaulicht, wie Node.js als Serveranwendung mit Expressverwendet wird.

Voraussetzungen

Um mit .NET.NET Aspirezu arbeiten, benötigen Sie folgendes lokal installiert:

Weitere Informationen finden Sie unter .NET.NET Aspire Setup und Toolingund .NET.NET Aspire SDK.

Darüber hinaus müssen Sie Node.js auf Ihrem Computer installieren. Die Beispiel-App in diesem Artikel wurde mit Node.js Version 20.12.2 und npm Version 10.5.1 erstellt. Führen Sie die folgenden Befehle aus, um ihre Node.js- und npm-Versionen zu überprüfen:

node --version
npm --version

Um Node.js (einschließlich npm) herunterzuladen, besuchen Sie die Node.js Download-Seite.

Clone-Beispielquellcode

Führen Sie den folgenden Befehl aus, um den Beispielquellcode aus GitHubzu klonen:

git clone https://github.com/dotnet/aspire-samples.git

Navigieren Sie nach dem Klonen des Repositorys zu den Samples/AspireWithJavaScript Ordner:

cd samples/AspireWithJavaScript

In diesem Verzeichnis gibt es sechs Unterverzeichnisse, die in der folgenden Liste beschrieben werden:

  • AspireJavaScript.Angular: Eine Angular-App, die die Wettervorhersage-API verwendet und die Daten in einer Tabelle anzeigt.
  • AspireJavaScript.AppHost: Ein .NET.NET Aspire Projekt, das die anderen Apps in diesem Beispiel koordiniert. Weitere Informationen finden Sie unter .NET.NET Aspire Orchestrierungsübersicht.
  • AspireJavaScript.MinimalApi: Eine HTTP-API, die zufällig generierte Wettervorhersagedaten zurückgibt.
  • AspireJavaScript.React: Eine React-App, die die Wettervorhersage-API verwendet und die Daten in einer Tabelle anzeigt.
  • AspireJavaScript.ServiceDefaults: Das gemeinsame Standardprojekt für .NET.NET Aspire Projekte. Weitere Informationen finden Sie unter .NET.NET Aspire Dienststandardeinstellungen.
  • AspireJavaScript.Vue: Eine Vue-App, die die Wettervorhersage-API verwendet und die Daten in einer Tabelle anzeigt.

Clientabhängigkeiten installieren

Die Beispiel-App veranschaulicht die Verwendung von JavaScript-Client-Apps, die auf Node.jsbasieren. Jede Client-App wurde entweder mithilfe eines npm create Vorlagenbefehls oder manuell geschrieben. In der folgenden Tabelle sind die Vorlagenbefehle aufgeführt, mit denen jede Client-App erstellt wird, zusammen mit dem Standardport:

App-Typ Befehl 'Vorlage erstellen' Standard-Port
Angular npm create @angular@latest 4200
React Es wurde keine Vorlage verwendet. PORT env var
Vue npm create vue@latest 5173

Trinkgeld

Sie müssen keinen dieser Befehle ausführen, da die Beispiel-App bereits die Clients enthält. Stattdessen ist dies ein Referenzpunkt, von dem die Clients erstellt wurden. Weitere Informationen finden Sie unter npm-init.

Zum Ausführen der App müssen Sie zuerst die Abhängigkeiten für jeden Client installieren. Navigieren Sie dazu zu jedem Clientordner und führen Sie die Befehle npm install (oder den Installationsalias npm i)aus.

Installiere Angular Abhängigkeiten

npm i ./AspireJavaScript.Angular/

Weitere Informationen zur Angular-App finden Sie unter , um den Angular-Clientzu erkunden.

Installiere React Abhängigkeiten

npm i ./AspireJavaScript.React/

Weitere Informationen zur React-App finden Sie unter Erkunden des React Client-.

Installiere Vue Abhängigkeiten

npm i ./AspireJavaScript.Vue/

Weitere Informationen zur Vue-App finden Sie im Abschnitt über die Verwendung des Vue-Clients.

Führen Sie die Beispielanwendung aus

Rufen Sie zum Ausführen der Beispiel-App den Befehl dotnet run auf, indem Sie den Orchestrator-App Host AspireJavaScript.AppHost.csproj als Schalter --project angeben.

dotnet run --project ./AspireJavaScript.AppHost/AspireJavaScript.AppHost.csproj

Das .NET.NET Aspire-Dashboard, in Ihrem Standardbrowser gestartet wird, und jeder Client-App-Endpunkt wird unter der Spalte Endpunkte Spalte der Seite Ressourcen angezeigt. Die folgende Abbildung zeigt das Dashboard für diese Beispiel-App:

.NET.NET Aspire Dashboard mit mehreren JavaScript-Client-Apps.

Der weatherapi-Dienstendpunkt leitet zu einer Swagger-UI-Seite weiter, die die HTTP-API dokumentiert. Jede Client-App verwendet diesen Dienst, um die Wettervorhersagedaten anzuzeigen. Sie können jede Client-App anzeigen, indem Sie im .NET.NET Aspire-Dashboard zum entsprechenden Endpunkt navigieren. Die Screenshots und die Änderungen, die am Anfangspunkt der Vorlage vorgenommen wurden, sind in den folgenden Abschnitten detailliert beschrieben.

Drücken Sie in derselben Terminalsitzung, die Sie zum Ausführen der App verwendet haben, STRG + + C, um die App zu stoppen.

Erkunden Sie den App-Host

Um zu verstehen, wie jede Client-App-Ressource koordiniert wird, suchen Sie nach dem App-Hostprojekt. Für den App-Host ist das Aspire.Hosting.NodeJS NuGet-Paket erforderlich, um die Node.js Apps zu hosten.

<Project Sdk="Microsoft.NET.Sdk">

  <Sdk Name="Aspire.AppHost.Sdk" Version="9.0.0" />

  <PropertyGroup>
    <OutputType>Exe</OutputType>
    <TargetFramework>net8.0</TargetFramework>
    <ImplicitUsings>enable</ImplicitUsings>
    <Nullable>enable</Nullable>
    <IsAspireHost>true</IsAspireHost>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="Aspire.Hosting.AppHost" Version="9.0.0" />
    <PackageReference Include="Aspire.Hosting.NodeJs" Version="9.0.0" />
  </ItemGroup>

  <ItemGroup>
    <ProjectReference Include="..\AspireJavaScript.MinimalApi\AspireJavaScript.MinimalApi.csproj" />
  </ItemGroup>

  <Target Name="RestoreNpm" BeforeTargets="Build" Condition=" '$(DesignTimeBuild)' != 'true' ">
    <ItemGroup>
      <PackageJsons Include="..\*\package.json" />
    </ItemGroup>

    <!-- Install npm packages if node_modules is missing -->
    <Message Importance="Normal" Text="Installing npm packages for %(PackageJsons.RelativeDir)" Condition="!Exists('%(PackageJsons.RootDir)%(PackageJsons.Directory)/node_modules')" />
    <Exec Command="npm install" WorkingDirectory="%(PackageJsons.RootDir)%(PackageJsons.Directory)" Condition="!Exists('%(PackageJsons.RootDir)%(PackageJsons.Directory)/node_modules')" />
  </Target>

</Project>

Die Projektdatei definiert auch ein Buildziel, das sicherstellt, dass die npm-Abhängigkeiten installiert werden, bevor der App-Host erstellt wird. Der App-Hostcode (Program.cs) deklariert die Client-App-Ressourcen mithilfe der AddNpmApp(IDistributedApplicationBuilder, String, String, String, String[])-API.

var builder = DistributedApplication.CreateBuilder(args);

var weatherApi = builder.AddProject<Projects.AspireJavaScript_MinimalApi>("weatherapi")
    .WithExternalHttpEndpoints();

builder.AddNpmApp("angular", "../AspireJavaScript.Angular")
    .WithReference(weatherApi)
    .WaitFor(weatherApi)
    .WithHttpEndpoint(env: "PORT")
    .WithExternalHttpEndpoints()
    .PublishAsDockerFile();

builder.AddNpmApp("react", "../AspireJavaScript.React")
    .WithReference(weatherApi)
    .WaitFor(weatherApi)
    .WithEnvironment("BROWSER", "none") // Disable opening browser on npm start
    .WithHttpEndpoint(env: "PORT")
    .WithExternalHttpEndpoints()
    .PublishAsDockerFile();

builder.AddNpmApp("vue", "../AspireJavaScript.Vue")
    .WithReference(weatherApi)
    .WaitFor(weatherApi)
    .WithHttpEndpoint(env: "PORT")
    .WithExternalHttpEndpoints()
    .PublishAsDockerFile();

builder.AddNpmApp("reactvite", "../AspireJavaScript.Vite")
    .WithReference(weatherApi)
    .WithEnvironment("BROWSER", "none")
    .WithHttpEndpoint(env: "VITE_PORT")
    .WithExternalHttpEndpoints()
    .PublishAsDockerFile();

builder.Build().Run();

Der vorangehende Code:

  • Erstellt eine DistributedApplicationBuilder.
  • Fügt dem App-Host den Dienst "weatherapi" als Projekt hinzu.
    • Markiert die HTTP-Endpunkte als extern.
  • Mit einem Verweis auf den "weatherapi"-Dienst werden die Client-Apps "angular", "react" und "vue" als npm-Apps hinzugefügt.
    • Jede Client-App ist für die Ausführung auf einem anderen Containerport konfiguriert und verwendet die umgebungsvariable PORT, um den Port zu bestimmen.
    • Alle Client-Apps basieren auch auf einem Dockerfile zum Erstellen ihres Containerimages und sind so konfiguriert, dass sie sich im Veröffentlichungsmanifest als Container aus der PublishAsDockerFile-API ausdrücken.

Weitere Informationen zu inneren Schleifennetzwerken finden Sie unter .NET.NET Aspire Übersicht über innere Schleifennetzwerke. Weitere Informationen zum Bereitstellen von Apps finden Sie im Manifestformat .NET.NET Aspire für die Entwicklung von Bereitstellungstools.

Wenn der App-Host den Start jeder Client-App koordiniert, wird der befehl npm run start verwendet. Dieser Befehl wird im abschnitt scripts der datei package.json für jede Client-App definiert. Das skript start wird verwendet, um die Client-App auf dem angegebenen Port zu starten. Jede Client-App basiert auf einem Proxy, um den "weatherapi"-Dienst anzufordern.

Der Proxy ist konfiguriert in:

  • Die proxy.conf.js Datei für den Angular-Client.
  • Die webpack.config.js Datei für den React-Client.
  • Die vite.config.ts Datei für den Vue-Client.

Erkunden des Angular-Clients

Es gibt mehrere wichtige Änderungen aus der ursprünglichen Angular Vorlage. Der erste ist das Hinzufügen einer proxy.conf.js Datei. Diese Datei wird verwendet, um Proxyanforderungen vom Angular-Client an den "weatherapi"-Dienst zu senden.

module.exports = {
  "/api": {
    target:
      process.env["services__weatherapi__https__0"] ||
      process.env["services__weatherapi__http__0"],
    secure: process.env["NODE_ENV"] !== "development",
    pathRewrite: {
      "^/api": "",
    },
  },
};

Der .NET.NET Aspire-Apphost legt die services__weatherapi__http__0-Umgebungsvariable fest, die zum auflösen des "weatherapi"-Dienstendpunkts verwendet wird. Die vorangehende Konfiguration leitet HTTP-Anforderungen, die mit /api beginnen, an die in der Umgebungsvariable angegebene Ziel-URL weiter.

Das zweite Update ist für die package.json Datei. Diese Datei wird verwendet, um den Angular-Client so zu konfigurieren, dass er auf einem anderen Port ausgeführt wird als der Standardport. Dies wird mithilfe der PORT Umgebungsvariablen und des run-script-os npm-Pakets erreicht, um den Port festzulegen.

{
  "name": "angular-weather",
  "version": "0.0.0",
  "engines": {
    "node": ">=20.12"
  },
  "scripts": {
    "ng": "ng",
    "start": "run-script-os",
    "start:win32": "ng serve --port %PORT%",
    "start:default": "ng serve --port $PORT",
    "build": "ng build",
    "watch": "ng build --watch --configuration development",
    "test": "ng test"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "^19.1.4",
    "@angular/common": "^19.1.4",
    "@angular/compiler": "^19.1.4",
    "@angular/core": "^19.1.4",
    "@angular/forms": "^19.1.4",
    "@angular/platform-browser": "^19.1.4",
    "@angular/platform-browser-dynamic": "^19.1.4",
    "@angular/router": "^19.1.4",
    "rxjs": "~7.8.1",
    "tslib": "^2.8.1",
    "zone.js": "~0.15.0"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^19.1.4",
    "@angular/cli": "^19.1.4",
    "@angular/compiler-cli": "^19.1.4",
    "@types/jasmine": "~5.1.5",
    "jasmine-core": "~5.5.0",
    "karma": "~6.4.4",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.1",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.7.3",
    "run-script-os": "^1.1.6"
  }
}

Der scripts Abschnitt der datei package.json wird verwendet, um das skript start zu definieren. Dieses Skript wird vom befehl npm start verwendet, um die Angular Client-App zu starten. Das Skript start ist so konfiguriert, dass das Paket run-script-os verwendet wird, um den Port festzulegen. Dieser Vorgang wird an den Befehl ng serve delegiert, der den entsprechenden Schalter --port basierend auf der für das Betriebssystem geeigneten Syntax übergibt.

Um HTTP-Aufrufe an den "weatherapi"-Dienst zu tätigen, muss die Angular-Client-App so konfiguriert werden, dass die AngularHttpClient für die Abhängigkeitseinfügung bereitgestellt wird. Dies wird mithilfe der provideHttpClient Hilfsfunktion erreicht, während die Anwendung in der app.config.ts Datei konfiguriert wird.

import { ApplicationConfig } from '@angular/core';
import { provideHttpClient } from '@angular/common/http';
import { provideRouter } from '@angular/router';

import { routes } from './app.routes';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient()
  ]
};

Schließlich muss die Angular-Client-App den /api/WeatherForecast Endpunkt aufrufen, um die Wettervorhersagedaten abzurufen. Es gibt mehrere HTML-, CSS- und TypeScript-Updates, die alle an den folgenden Dateien vorgenommen werden:

import { Component, Injectable } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { WeatherForecasts } from '../types/weatherForecast';

@Injectable()
@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
  title = 'weather';
  forecasts: WeatherForecasts = [];

  constructor(private http: HttpClient) {
    http.get<WeatherForecasts>('api/weatherforecast').subscribe({
      next: result => this.forecasts = result,
      error: console.error
    });
  }
}

Angular laufende App

Um die Angular Client-App zu visualisieren, navigieren Sie im .NET Aspire-Dashboard zum "angular"-Endpunkt. Die folgende Abbildung zeigt die Angular Client-App:

Angular Client-App mit gefälschten Wettervorhersagedaten, die als Tabelle angezeigt werden.

Erkunden des React-Clients

Die React-App wurde nicht mit einer Vorlage geschrieben und wurde stattdessen manuell geschrieben. Der vollständige Quellcode finden Sie im dotnet/aspire-samples Repository. Einige der wichtigsten Interessanten Punkte finden Sie in der Datei src/App.js:

import { useEffect, useState } from "react";
import "./App.css";

function App() {
  const [forecasts, setForecasts] = useState([]);

  const requestWeather = async () => {
    const weather = await fetch("api/weatherforecast");
    console.log(weather);

    const weatherJson = await weather.json();
    console.log(weatherJson);

    setForecasts(weatherJson);
  };

  useEffect(() => {
    requestWeather();
  }, []);

  return (
    <div className="App">
      <header className="App-header">
        <h1>React Weather</h1>
        <table>
          <thead>
            <tr>
              <th>Date</th>
              <th>Temp. (C)</th>
              <th>Temp. (F)</th>
              <th>Summary</th>
            </tr>
          </thead>
          <tbody>
            {(
              forecasts ?? [
                {
                  date: "N/A",
                  temperatureC: "",
                  temperatureF: "",
                  summary: "No forecasts",
                },
              ]
            ).map((w) => {
              return (
                <tr key={w.date}>
                  <td>{w.date}</td>
                  <td>{w.temperatureC}</td>
                  <td>{w.temperatureF}</td>
                  <td>{w.summary}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      </header>
    </div>
  );
}

export default App;

Die App-Funktion ist der Einstiegspunkt für die React-Client-App. Es verwendet die useState und useEffect Hooks, um den Zustand der Wettervorhersagedaten zu verwalten. Die fetch-API wird verwendet, um eine HTTP-Anforderung an den /api/WeatherForecast Endpunkt zu senden. Die Antwort wird dann in JSON konvertiert und als Status der Wettervorhersagedaten festgelegt.

const HTMLWebpackPlugin = require("html-webpack-plugin");

module.exports = (env) => {
  return {
    entry: "./src/index.js",
    devServer: {
      port: env.PORT || 4001,
      allowedHosts: "all",
      proxy: [
        {
          context: ["/api"],
          target:
            process.env.services__weatherapi__https__0 ||
            process.env.services__weatherapi__http__0,
          pathRewrite: { "^/api": "" },
          secure: false,
        },
      ],
    },
    output: {
      path: `${__dirname}/dist`,
      filename: "bundle.js",
    },
    plugins: [
      new HTMLWebpackPlugin({
        template: "./src/index.html",
        favicon: "./src/favicon.ico",
      }),
    ],
    module: {
      rules: [
        {
          test: /\.js$/,
          exclude: /node_modules/,
          use: {
            loader: "babel-loader",
            options: {
              presets: [
                "@babel/preset-env",
                ["@babel/preset-react", { runtime: "automatic" }],
              ],
            },
          },
        },
        {
          test: /\.css$/,
          exclude: /node_modules/,
          use: ["style-loader", "css-loader"],
        },
      ],
    },
  };
};

Der vorangehende Code definiert das module.exports wie folgt:

  • Die entry-Eigenschaft wird auf die Datei src/index.js festgelegt.
  • Die devServer verwendet einen Proxy, um Anforderungen an den "weatherapi"-Dienst weiterzuleiten, setzt den Port auf die Umgebungsvariable PORT und erlaubt alle Hosts.
  • Das output führt zu einem dist-Ordner mit einer bundle.js-Datei.
  • Der plugins legte die src/index.html-Datei als Vorlage fest und gab die favicon.ico-Datei frei.

Die endgültigen Updates betreffen die folgenden Dateien:

React laufende App

Um die React Client-App zu visualisieren, navigieren Sie im .NET Aspire-Dashboard zum Endpunkt "react". Die folgende Abbildung zeigt die React Client-App:

React Client-App mit gefälschten Wettervorhersagedaten, die als Tabelle angezeigt werden.

Erkunden des Vue-Clients

Es gibt mehrere wichtige Änderungen aus der ursprünglichen Vue Vorlage. Die primären Updates waren das Hinzufügen des fetch Aufrufs in der Datei TheWelcome.vue, um die Wettervorhersagedaten vom /api/WeatherForecast Endpunkt abzurufen. Der folgende Codeausschnitt veranschaulicht den fetch Aufruf:

<script lang="ts">
interface WeatherForecast {
  date: string
  temperatureC: number
  temperatureF: number
  summary: string
};

type Forecasts = WeatherForecast[];

export default {
  name: 'TheWelcome',
  data() {
    return {
      forecasts: [],
      loading: true,
      error: null
    }
  },
  mounted() {
    fetch('api/weatherforecast')
      .then(response => response.json())
      .then(data => {
        this.forecasts = data
      })
      .catch(error => {
        this.error = error
      })
      .finally(() => (this.loading = false))
  }
}
</script>

<template>
  <table>
    <thead>
      <tr>
        <th>Date</th>
        <th>Temp. (C)</th>
        <th>Temp. (F)</th>
        <th>Summary</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="forecast in (forecasts as Forecasts)">
        <td>{{ forecast.date }}</td>
        <td>{{ forecast.temperatureC }}</td>
        <td>{{ forecast.temperatureF }}</td>
        <td>{{ forecast.summary }}</td>
      </tr>
    </tbody>
  </table>
</template>

<style>
table {
  border: none;
  border-collapse: collapse;
}

th {
  font-size: x-large;
  font-weight: bold;
  border-bottom: solid .2rem hsla(160, 100%, 37%, 1);
}

th,
td {
  padding: 1rem;
}

td {
  text-align: center;
  font-size: large;
}

tr:nth-child(even) {
  background-color: var(--vt-c-black-soft);
}
</style>

Wenn die TheWelcome-Integration mountedist, ruft sie den /api/weatherforecast-Endpunkt auf, um die Wettervorhersagedaten abzurufen. Die Antwort wird dann als forecasts-Dateneigenschaft festgelegt. Um den Serverport festzulegen, verwendet die Vue Client-App die PORT Umgebungsvariable. Dies wird durch Aktualisieren der vite.config.ts Datei erreicht:

import { fileURLToPath, URL } from 'node:url'

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [
    vue(),
  ],
  resolve: {
    alias: {
      '@': fileURLToPath(new URL('./src', import.meta.url))
    }
  },
  server: {
    host: true,
    port: parseInt(process.env.PORT ?? "5173"),
    proxy: {
      '/api': {
        target: process.env.services__weatherapi__https__0 || process.env.services__weatherapi__http__0,
        changeOrigin: true,
        rewrite: path => path.replace(/^\/api/, ''),
        secure: false
      }
    }
  }
})

Darüber hinaus legt die Vite-Konfiguration die Eigenschaft server.proxy fest, um Anforderungen an den "weatherapi"-Dienst weiterzuleiten. Dies wird mithilfe der services__weatherapi__http__0 Umgebungsvariablen erreicht, die vom .NET.NET Aspire App-Host festgelegt wird.

Die endgültige Aktualisierung der Vorlage wird in die Datei TheWelcome.vue vorgenommen. Diese Datei ruft den /api/WeatherForecast Endpunkt auf, um die Wettervorhersagedaten abzurufen, und zeigt die Daten in einer Tabelle an. Sie enthält CSS-, HTML- und TypeScript-Updates.

Vue laufende App

Um die Vue Client-App zu visualisieren, navigieren Sie im .NET Aspire-Dashboard zum Endpunkt "vue". Die folgende Abbildung zeigt die Vue Client-App:

Vue Client-App mit gefälschten Wettervorhersagedaten, die als Tabelle angezeigt werden.

Überlegungen zur Bereitstellung

Der Beispielquellcode für diesen Artikel wurde für die lokale Ausführung entwickelt. Jede Client-App wird als Container-Image bereitgestellt. Die Dockerfile für jede Client-Anwendung wird verwendet, um das Container-Image zu erstellen. Um ein produktionsfähiges Container-Image zu erstellen, wird ein mehrstufiger Build verwendet, wobei jede Dockerfile identisch ist.

FROM node:20 as build

WORKDIR /app

COPY package.json package.json
COPY package-lock.json package-lock.json

RUN npm install

COPY . .

RUN npm run build

FROM nginx:alpine

COPY --from=build /app/default.conf.template /etc/nginx/templates/default.conf.template
COPY --from=build /app/dist/weather/browser /usr/share/nginx/html

# Expose the default nginx port
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

Die Client-Apps sind derzeit so konfiguriert, dass sie als echte SPA-Apps ausgeführt werden und nicht für die Ausführung in einem serverseitigen gerenderten Modus (SSR) konfiguriert sind. Sie sitzen hinter nginx, die verwendet wird, um die statischen Dateien zu bedienen. Sie verwenden eine default.conf.template- Datei, um nginx- für Proxyanforderungen an die Client-App zu konfigurieren.

server {
    listen       ${PORT};
    listen  [::]:${PORT};
    server_name  localhost;

    access_log  /var/log/nginx/server.access.log  main;

    location / {
        root /usr/share/nginx/html;
        try_files $uri $uri/ /index.html;
    }

    location /api/ {
        proxy_pass ${services__weatherapi__https__0};
        proxy_http_version 1.1;
        proxy_ssl_server_name on;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        rewrite ^/api(/.*)$ $1 break;
    }
}

Überlegungen zur Node.js Server-App

Während sich dieser Artikel auf Client-Apps konzentriert, können Sie Szenarien haben, in denen Sie eine Node.js Server-App hosten müssen. Die gleiche Semantik ist erforderlich, um eine Node.js Server-App als SPA-Client-App zu hosten. Für den .NET.NET Aspire App-Host ist ein Paketverweis auf das Aspire.Hosting.NodeJS NuGet-Paket erforderlich, und der Code muss entweder AddNodeApp oder AddNpmAppaufrufen. Diese APIs eignen sich zum Hinzufügen vorhandener JavaScript-Apps zum .NET.NET Aspire App-Host.

Verwenden Sie beim Konfigurieren geheimer Schlüssel und Übergeben von Umgebungsvariablen an JavaScript-basierte Apps, unabhängig davon, ob es sich um Client- oder Server-Apps handelt, Parameter. Weitere Informationen finden Sie unter .NET.NET Aspire– Externe Parameter: die Geheimnisse.

Verwenden Sie das OpenTelemetry JavaScript SDK

Um OpenTelemetry Protokolle, Traces und Metriken aus einer Node.js Server-App zu exportieren, verwenden Sie das OpenTelemetry JavaScript SDK.

Ein vollständiges Beispiel für eine Node.js Server-App mit dem OpenTelemetry JavaScript SDK finden Sie unter den Codebeispielen auf der .NET AspireNode.js Musterseite. Betrachten Sie die Beispieldatei instrumentation.js, die veranschaulicht, wie Sie das OpenTelemetry JavaScript SDK zum Exportieren von Protokollen, Traces und Metriken konfigurieren:

import { env } from 'node:process';
import { NodeSDK } from '@opentelemetry/sdk-node';
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-grpc';
import { OTLPMetricExporter } from '@opentelemetry/exporter-metrics-otlp-grpc';
import { OTLPLogExporter } from '@opentelemetry/exporter-logs-otlp-grpc';
import { SimpleLogRecordProcessor } from '@opentelemetry/sdk-logs';
import { PeriodicExportingMetricReader } from '@opentelemetry/sdk-metrics';
import { HttpInstrumentation } from '@opentelemetry/instrumentation-http';
import { ExpressInstrumentation } from '@opentelemetry/instrumentation-express';
import { RedisInstrumentation } from '@opentelemetry/instrumentation-redis-4';
import { diag, DiagConsoleLogger, DiagLogLevel } from '@opentelemetry/api';
import { credentials } from '@grpc/grpc-js';

const environment = process.env.NODE_ENV || 'development';

// For troubleshooting, set the log level to DiagLogLevel.DEBUG
//diag.setLogger(new DiagConsoleLogger(), environment === 'development' ? DiagLogLevel.INFO : DiagLogLevel.WARN);

const otlpServer = env.OTEL_EXPORTER_OTLP_ENDPOINT;

if (otlpServer) {
    console.log(`OTLP endpoint: ${otlpServer}`);

    const isHttps = otlpServer.startsWith('https://');
    const collectorOptions = {
        credentials: !isHttps
            ? credentials.createInsecure()
            : credentials.createSsl()
    };

    const sdk = new NodeSDK({
        traceExporter: new OTLPTraceExporter(collectorOptions),
        metricReader: new PeriodicExportingMetricReader({
            exportIntervalMillis: environment === 'development' ? 5000 : 10000,
            exporter: new OTLPMetricExporter(collectorOptions),
        }),
        logRecordProcessor: new SimpleLogRecordProcessor({
            exporter: new OTLPLogExporter(collectorOptions)
        }),
        instrumentations: [
            new HttpInstrumentation(),
            new ExpressInstrumentation(),
            new RedisInstrumentation()
        ],
    });

    sdk.start();
}

Trinkgeld

Informationen zum Konfigurieren der .NET.NET Aspire-Dashboard-OTEL CORS-Einstellungen finden Sie auf der .NET.NET Aspire Dashboard-OTEL CORS-Einstellungen Seite.

Zusammenfassung

Obwohl es mehrere Überlegungen gibt, die über den Umfang dieses Artikels hinausgehen, haben Sie erfahren, wie Sie .NET Aspire Projekte erstellen, die Node.js und Node Package Manager (npm) verwenden. Außerdem haben Sie erfahren, wie Sie die AddNpmApp-APIs verwenden, um Node.js Apps und Apps zu hosten, die aus einer package.json Datei ausgeführt werden. Schließlich haben Sie erfahren, wie Sie die npm CLI zum Erstellen von Angular, Reactund Vue Client-Apps verwenden und wie Sie sie für die Ausführung auf verschiedenen Ports konfigurieren.

Siehe auch