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 Vueclient Erfahrungen. 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 erstere zum Hosten von Node.js-Apps verwendet wird, während die letztere zum Hosten von Apps verwendet wird, die aus einem -Paket ausgeführt werden.json-Abschnitt in der scripts-Datei und der entsprechende 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-Frontend-Bits (SPA) konzentriert, gibt es ein zusätzliches Node.js-Beispiel auf der -Codebeispiele: .NET AspireNode.js-Beispiel--Seite, das zeigt, wie man Node.js als server-App mit Express-verwendet.

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.

Installiere client Abhängigkeiten

Die Beispielanwendung 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 jede clientinstallieren. Navigieren Sie dazu zu jedem client Ordner, und führen Sie den Befehl npm install (oder das Installations-Alias npm i)aus.

Installieren Sie Angular Abhängigkeiten

npm i ./AspireJavaScript.Angular/

Weitere Informationen zur Angular-App finden Sie unter Erkunden des Angularclient.

Installiere React Abhängigkeiten

npm i ./AspireJavaScript.React/

Weitere Informationen zur React-App finden Sie unter , um Reactclientzu erkunden.

Installiere Vue Abhängigkeiten

npm i ./AspireJavaScript.Vue/

Weitere Informationen zur Vue-App finden Sie unter , um das Vueclientzu entdecken.

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 wird in Ihrem Standardbrowser gestartet, und jeder client App-Endpunkt wird unter der Endpunkte-Spalte der Ressourcen-Seite angezeigt. Die folgende Abbildung zeigt das Dashboard für diese Beispiel-App:

.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 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 orchestriert wird, schauen Sie sich das App-Hostprojekt an. 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.
  • Fügt mit einem Verweis auf den "weatherapi"-Dienst die "angular", "react" und "vue" client Apps als npm-Apps hinzu.
    • Jede client-App ist so konfiguriert, dass sie auf einem anderen Containerport ausgeführt wird, und verwendet die PORT Umgebungsvariable, um den Port zu bestimmen.
    • Alle client Apps setzen auch auf einen Dockerfile, um ihr Container-Abbild zu erstellen, und sind so konfiguriert, dass sie im Veröffentlichungsmanifest als ein Container der PublishAsDockerFile-API ausgewiesen werden.

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 orchestriert, verwendet er den Befehl npm run start. Dieser Befehl wird im abschnitt scripts des -Pakets definiert.json Datei für jede client App. Das skript start wird verwendet, um die client App am angegebenen Port zu starten. Jede client-App nutzt einen Proxy, um den "weatherapi"-Dienst aufzurufen.

Der Proxy ist konfiguriert in:

  • Die proxy.conf.js Datei für die Angularclient.
  • Die webpack.config.js Datei für die Reactclient.
  • Die .ts-Datei von vite.configfür .

Entdecken Sie die Angularclient

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 Angularclient 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 betrifft das -Paket. Dateijson. Diese Datei wird verwendet, um die Angularclient für die Ausführung auf einem anderen Port als dem Standardport zu konfigurieren. 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": "^18.1.1",
    "@angular/common": "^18.1.1",
    "@angular/compiler": "^18.1.1",
    "@angular/core": "^18.1.1",
    "@angular/forms": "^18.1.1",
    "@angular/platform-browser": "^18.1.1",
    "@angular/platform-browser-dynamic": "^18.1.1",
    "@angular/router": "^18.1.1",
    "rxjs": "~7.8.0",
    "tslib": "^2.6.3",
    "zone.js": "~0.14.8"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "^18.1.1",
    "@angular/cli": "^18.1.1",
    "@angular/compiler-cli": "^18.1.1",
    "@types/jasmine": "~5.1.0",
    "jasmine-core": "~5.2.0",
    "karma": "~6.4.3",
    "karma-chrome-launcher": "~3.2.0",
    "karma-coverage": "~2.2.0",
    "karma-jasmine": "~5.1.0",
    "karma-jasmine-html-reporter": "~2.1.0",
    "typescript": "~5.5.3",
    "run-script-os": "^1.1.6"
  }
}

Der scripts Abschnitt des -Pakets.json Datei wird verwendet, um das start Skript zu definieren. Dieses Skript wird vom Befehl npm start verwendet, um die Angularclient 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 senden, muss die Angularclient-App so konfiguriert werden, dass die AngularHttpClient für die Abhängigkeitsinjektion 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 Angularclient-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 Angularclient-App zu visualisieren, navigieren Sie im .NET Aspire-Dashboard zum Endpunkt "angular". Die folgende Abbildung zeigt die Angularclient-App:

Angularclient App mit gefälschten Wettervorhersagedaten, die als Tabelle angezeigt werden.

Entdecken Sie die Reactclient

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 Reactclient-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 Reactclient-App zu visualisieren, navigieren Sie im .NET Aspire-Dashboard zum Endpunkt "react". Die folgende Abbildung zeigt die Reactclient-App:

Reactclient App mit gefälschten Wettervorhersagedaten, die als Tabelle angezeigt werden.

Entdecken Sie die Vueclient

Es gibt mehrere wichtige Änderungen an der ursprünglichen Vue-Vorlage. Die primären Updates waren das Hinzufügen des fetch-Aufrufs in der TheWelcome-vue--Datei, um die Wettervorhersage-Daten 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 server-Port festzulegen, verwendet die Vueclient-App die umgebungsvariable PORT. 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 erfolgt in der TheWelcome.vue Datei. 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 Vueclient-App zu visualisieren, navigieren Sie im .NET Aspire-Dashboard zum Endpunkt "vue". Die folgende Abbildung zeigt die Vueclient-App:

Vueclient 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-App 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 server-side renderten Modus (SSR) konfiguriert sind. Sie sitzen hinter nginx, die verwendet wird, um die statischen Dateien zu bedienen. Sie verwenden eine Datei mit dem Namen default.conf.template, um nginx so zu konfigurieren, dass Anfragen an die client App weitergeleitet werden.

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.jsserver App

Während sich dieser Artikel auf client-Apps konzentriert, können Sie Szenarien haben, in denen Sie eine Node.jsserver-App hosten müssen. Die gleiche Semantik ist erforderlich, um eine Node.jsserver-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 Parameter 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. Weitere Informationen finden Sie unter .NET.NET Aspire– Externe Parameter: die Geheimnisse.

Verwenden Sie das OpenTelemetry JavaScript SDK

Um OpenTelemetry Protokolle, Ablaufverfolgungen und Metriken aus einer Node.jsserver-App zu exportieren, verwenden Sie das OpenTelemetry JavaScript SDK-.

Ein vollständiges Beispiel für eine Node.jsserver-App mit dem OpenTelemetry JavaScript SDK finden Sie auf der Seite Code-Beispiele: .NET AspireNode.js Beispiel. 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 gelernt, wie Sie die AddNpmApp-APIs verwenden, um Node.js-Anwendungen zu hosten und Anwendungen aus einem -Paket auszuführen bzw.json- und-Dateien. Schließlich haben Sie erfahren, wie Sie die npm CLI zum Erstellen von Angular, Reactund Vueclient Apps verwenden und wie Sie sie für die Ausführung auf verschiedenen Ports konfigurieren.

Siehe auch