Udostępnij za pośrednictwem


Orkiestracja aplikacji Node.js w .NET Aspire

Z tego artykułu dowiesz się, jak używać aplikacji Node.js i Node Package Manager (npm) w projekcie .NET.NET Aspire. Przykładowa aplikacja w tym artykule pokazuje środowiska Angular, Reacti Vue,client. Następujące interfejsy API .NET.NET Aspire istnieją, aby obsługiwać te scenariusze — i są one częścią Aspire. Hosting.NodeJS pakiet NuGet:

Różnica między tymi dwoma interfejsami API polega na tym, że pierwszy jest używany do hostowania aplikacji Node.js, podczas gdy ten ostatni służy do hostowania aplikacji wykonywanych z pakietu . Sekcja scripts plikujson oraz odpowiadające jej polecenie npm run <script-name>.

Napiwek

Przykładowy kod źródłowy tego artykułu jest dostępny w witrynie GitHubi są dostępne szczegółowe informacje na stronie przykłady kodu : .NET Aspire z Angular, React i Vue.

Ważny

Chociaż ten artykuł koncentruje się na elementach frontendu aplikacji Single-Page (SPA), na stronie z przykładami kodu znajduje się dodatkowy przykład Node.js: .NET AspireNode.js, który pokazuje, jak używać Node.js jako aplikacji server z użyciem express.

Warunki wstępne

Aby pracować z .NET.NET Aspire, musisz mieć zainstalowane lokalnie następujące elementy:

Aby uzyskać więcej informacji, zobacz .NET.NET Aspire setup and toolingi .NET.NET Aspire SDK.

Ponadto należy zainstalować Node.js na maszynie. Przykładowa aplikacja w tym artykule została skompilowana przy użyciu Node.js w wersji 20.12.2 i narzędzia npm w wersji 10.5.1. Aby zweryfikować wersje Node.js i npm, uruchom następujące polecenia:

node --version
npm --version

Aby pobrać Node.js (w tym npm), zobacz stronę pobierania Node.js.

Klonowanie przykładowego kodu źródłowego

Aby sklonować przykładowy kod źródłowy z GitHub, uruchom następujące polecenie:

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

Po sklonowaniu repozytorium przejdź do folderu samples/AspireWithJavaScript:

cd samples/AspireWithJavaScript

Z tego katalogu istnieje sześć katalogów podrzędnych opisanych na poniższej liście:

  • AspireJavaScript.Angular: aplikacja Angular, która wykorzystuje API prognoz pogody i wyświetla dane w tabeli.
  • AspireJavaScript.AppHost: projekt .NET.NET Aspire, który organizuje inne aplikacje w tym przykładzie. Aby uzyskać więcej informacji, zobacz omówienie orkiestracji .NET.NET Aspire.
  • AspireJavaScript.MinimalApi: interfejs API HTTP, który zwraca losowo wygenerowane dane prognozy pogody.
  • AspireJavaScript.React: Aplikacja React, która korzysta z interfejsu API prognozy pogody i wyświetla dane w tabeli.
  • AspireJavaScript.ServiceDefaults: domyślny udostępniony projekt dla projektów .NET.NET Aspire. Aby uzyskać więcej informacji, zobacz ustawienia domyślne usługi .NET.NET Aspire.
  • AspireJavaScript.Vue: aplikacja Vue, która wykorzystuje API prognozy pogody i wyświetla dane w tabeli.

Instalowanie zależności client

Przykładowa aplikacja pokazuje, jak używać aplikacji client JavaScript opartych na Node.js. Każda aplikacja client została napisana przy użyciu polecenia szablonu npm create lub ręcznie. W poniższej tabeli wymieniono polecenia szablonu używane do tworzenia każdej aplikacji client wraz z portem domyślnym:

Typ aplikacji Polecenie Create template (Tworzenie szablonu) Port domyślny
Angular npm create @angular@latest 4200
React Nie użyto szablonu. Port env var
Vue npm create vue@latest 5173

Napiwek

Nie musisz uruchamiać żadnego z tych poleceń, ponieważ przykładowa aplikacja zawiera już klientów. Zamiast tego jest to punkt odniesienia, na podstawie którego stworzono klientów. Aby uzyskać więcej informacji, zobacz npm-init.

Aby uruchomić aplikację, należy najpierw zainstalować zależności dla każdego client. W tym celu przejdź do każdego folderu client i uruchom polecenia npm install (lub aliasu instalacji npm i).

Instalowanie zależności Angular

npm i ./AspireJavaScript.Angular/

Aby uzyskać więcej informacji na temat aplikacji Angular, sprawdź i przeanalizuj Angularclient.

Instalowanie zależności React

npm i ./AspireJavaScript.React/

Aby uzyskać więcej informacji na temat aplikacji React, zobacz i zbadaj Reactclient.

Instalowanie zależności Vue

npm i ./AspireJavaScript.Vue/

Aby uzyskać więcej informacji na temat aplikacji Vue, zobacz i eksploruj Vueclient.

Uruchamianie przykładowej aplikacji

Aby uruchomić przykładową aplikację, wywołaj polecenie dotnet run, przy użyciu hosta aplikacji orkiestratora AspireJavaScript.AppHost.csproj jako przełącznik --project.

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

Pulpit nawigacyjny jest uruchamiany w domyślnej przeglądarce, a każdy punkt końcowy aplikacji jest wyświetlany w kolumnie Endpoints (Punkty końcowe ) na stronie Resources. Na poniższej ilustracji przedstawiono pulpit nawigacyjny dla tej przykładowej aplikacji:

.NET Aspire pulpit nawigacyjny z wieloma aplikacjami client JavaScript.

Punkt końcowy usługi weatherapi prowadzi do strony Swagger UI dokumentującej interfejs API HTTP. Każda aplikacja client używa tej usługi do wyświetlania danych prognozy pogody. Każdą aplikację client można wyświetlić, przechodząc do odpowiedniego punktu końcowego na pulpicie nawigacyjnym .NET Aspire. Ich zrzuty ekranu i modyfikacje wprowadzone z punktu początkowego szablonu zostały szczegółowo opisane w poniższych sekcjach.

W tej samej sesji terminalu, która była używana do uruchamiania aplikacji, naciśnij Ctrl + C, aby zatrzymać aplikację.

Eksplorowanie hosta aplikacji

Aby dowiedzieć się, jak każdy zasób aplikacji client jest zorganizowany, zapoznaj się z projektem hosta aplikacji. Host aplikacji wymaga pakietu NuGet Aspire.Hosting.NodeJS do hostowania aplikacji Node.js.

<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>

Plik projektu definiuje również cel kompilacji, który gwarantuje, że zależności npm są instalowane przed skompilowaniem hosta aplikacji. Kod hosta aplikacji (Program.cs) deklaruje zasoby aplikacji client przy użyciu interfejsu API AddNpmApp(IDistributedApplicationBuilder, String, String, String, String[]).

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();

Powyższy kod:

  • Tworzy DistributedApplicationBuilder.
  • Dodaje usługę "weatherapi" jako projekt do hosta aplikacji.
    • Oznacza punkty końcowe HTTP jako zewnętrzne.
  • Z odwołaniem do usługi "weatherapi" dodaje "angular", "react", i "vue" client jako aplikacje npm.
    • Każda aplikacja client jest skonfigurowana do uruchamiania na innym porcie kontenera i używa zmiennej środowiskowej PORT do określenia portu.
    • Wszystkie aplikacje client również polegają na Dockerfile do tworzenia obrazu kontenera i są skonfigurowane do wyrażania siebie w manifeście publikowania jako kontenera z interfejsu API PublishAsDockerFile.

Aby uzyskać więcej informacji na temat sieci pętli wewnętrznej, zobacz .NET.NET Aspire omówienie sieci pętli wewnętrznej. Aby uzyskać więcej informacji na temat wdrażania aplikacji, zobacz .NET.NET Aspire format manifestu dla konstruktorów narzędzi wdrażania.

Gdy host aplikacji organizuje uruchamianie każdej aplikacji client, używa polecenia npm run start. To polecenie jest definiowane w sekcji scripts pakietu .json plik dla każdej aplikacji client. Skrypt start służy do uruchamiania aplikacji client na określonym porcie. Każda aplikacja client korzysta z serwera proxy, aby zażądać usługi "weatherapi".

Serwer proxy jest skonfigurowany w:

  • Plik proxy.conf.js dla Angularclient.
  • Plik webpack.config.js dla Reactclient.
  • Plik vite.config.ts dla Vueclient.

Eksploruj Angularclient

Istnieje kilka kluczowych modyfikacji oryginalnego szablonu Angular. Pierwszy to dodanie pliku proxy.conf.js. Ten plik jest używany do proxy'owania żądań z Angularclient do usługi "weatherapi".

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

Host aplikacji .NET.NET Aspire ustawia zmienną środowiskową services__weatherapi__http__0, która służy do rozpoznawania punktu końcowego usługi "weatherapi". Poprzednia konfiguracja proxy kieruje żądania HTTP rozpoczynające się od /api do docelowego adresu URL określonego w zmiennej środowiskowej.

Druga aktualizacja dotyczy pakietu , plikujson. Ten plik służy do konfigurowania Angularclient do uruchamiania na innym porcie niż port domyślny. Jest to osiągane przy użyciu zmiennej środowiskowej PORT, a pakiet run-script-os npm w celu ustawienia portu.

{
  "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"
  }
}

Sekcja scripts pakietu . plikjson służy do definiowania skryptu start. Ten skrypt jest używany przez polecenie npm start, aby uruchomić aplikację Angularclient. Skrypt start jest skonfigurowany do korzystania z pakietu run-script-os w celu ustawienia portu, delegując do polecenia ng serve i przekazując odpowiedni przełącznik --port na podstawie składni właściwej dla danego systemu operacyjnego.

Aby wykonać wywołania HTTP do usługi "weatherapi", aplikacja Angularclient musi być skonfigurowana tak, aby zapewnić AngularHttpClient do wstrzykiwania zależności. Jest to osiągane przy użyciu funkcji pomocnika provideHttpClient podczas konfigurowania aplikacji w pliku app.config.ts.

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()
  ]
};

Na koniec aplikacja Angularclient musi wywołać punkt końcowy /api/WeatherForecast, aby pobrać dane prognozy pogody. Istnieje kilka aktualizacji HTML, CSS i TypeScript, z których wszystkie są wykonywane w następujących plikach:

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 aplikacja działa

Aby zwizualizować aplikację Angularclient, przejdź do punktu końcowego "angular" na pulpicie nawigacyjnym .NET Aspire. Na poniższej ilustracji przedstawiono aplikację Angularclient:

Angularclient aplikacja z fałszywymi danymi prognozy pogody wyświetlanymi jako tabela.

Eksplorowanie Reactclient

Aplikacja React nie została napisana przy użyciu szablonu i została napisana ręcznie. Kompletny kod źródłowy można znaleźć w repozytorium dotnet/aspire-samples. Niektóre kluczowe punkty orientacyjne znajdują się w pliku 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;

Funkcja App jest punktem wejścia aplikacji Reactclient. Używa hooków useState i useEffect do zarządzania stanem danych prognozy pogody. Interfejs API fetch służy do żądania HTTP do punktu końcowego /api/WeatherForecast. Odpowiedź jest następnie konwertowana na JSON i ustawiana jako stan danych prognozy pogody.

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"],
        },
      ],
    },
  };
};

Powyższy kod definiuje module.exports w następujący sposób:

  • Właściwość entry jest ustawiona na plik src/index.js.
  • devServer używa serwera proxy do przekazywania żądań do usługi "weatherapi", ustawia port według zmiennej środowiskowej PORT i zezwala na dostęp dla wszystkich hostów.
  • Wyniki znajdują się w folderze zawierającym plik bundle.js.
  • plugins ustawić plik src/index.html jako szablon i uwidocznić plik favicon.ico.

Ostateczne aktualizacje dotyczą następujących plików:

React uruchomiona aplikacja

Aby zwizualizować aplikację Reactclient, przejdź do punktu końcowego "react" na pulpicie nawigacyjnym .NET Aspire. Na poniższej ilustracji przedstawiono aplikację Reactclient:

Reactclient aplikacja z fałszywymi danymi prognoz pogody wyświetlana jako tabela.

Eksplorowanie Vueclient

Istnieje kilka kluczowych modyfikacji oryginalnego szablonu Vue. Podstawowe aktualizacje obejmowały dodanie wywołania fetch w pliku TheWelcomevue, aby pobrać dane prognozy pogody z punktu końcowego /api/WeatherForecast. Poniższy fragment kodu przedstawia wywołanie fetch:

<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>

Ponieważ integracja TheWelcome jest mounted, wywołuje punkt końcowy /api/weatherforecast, aby pobrać dane prognozy pogody. Odpowiedź jest następnie ustawiana jako właściwość danych forecasts. Aby ustawić port server, aplikacja Vueclient używa zmiennej środowiskowej PORT. Można to osiągnąć przez zaktualizowanie pliku vite.config.ts:

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
      }
    }
  }
})

Ponadto konfiguracja vite określa właściwość server.proxy do przekazywania żądań do usługi "weatherapi". Jest to osiągane przy użyciu zmiennej środowiskowej services__weatherapi__http__0, która jest ustawiana przez hosta aplikacji .NET.NET Aspire.

Ostateczna aktualizacja szablonu jest wprowadzana do pliku TheWelcome.vue. Ten plik wywołuje endpoint /api/WeatherForecast w celu pobrania danych prognozy pogody i wyświetla dane w tabeli. Obejmuje ona aktualizacje CSS, HTML i TypeScript.

Vue uruchomiona aplikacja

Aby zwizualizować aplikację Vueclient, przejdź do punktu końcowego "vue" na pulpicie nawigacyjnym .NET Aspire. Na poniższej ilustracji przedstawiono aplikację Vueclient:

Vueclient aplikacja z fałszywymi danymi prognozy pogody wyświetlanymi jako tabela.

Zagadnienia dotyczące wdrażania

Przykładowy kod źródłowy tego artykułu jest przeznaczony do uruchamiania lokalnie. Każda aplikacja client jest wdrażana jako obraz kontenera. Dockerfile dla każdej aplikacji client służy do kompilowania obrazu kontenera. Każda Dockerfile jest identyczna, korzystając z kompilacji wielostopniowej do utworzenia obrazu kontenera gotowego do produkcji.

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;"]

Aplikacje client są obecnie skonfigurowane do uruchamiania jako aplikacje SPA i nie są skonfigurowane do uruchamiania z renderowaniem po stronie server(SSR). Znajdują się one za nginx, który służy do obsługi plików statycznych. Używają pliku default.conf.template do konfigurowania nginx na żądania serwera proxy do aplikacji .

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;
    }
}

Node.js server zagadnienia dotyczące aplikacji

Chociaż ten artykuł koncentruje się na aplikacjach client, mogą wystąpić sytuacje, w których trzeba hostować aplikację Node.jsserver. Taka sama semantyka jest wymagana do hostowania aplikacji Node.jsserver jako aplikacji SPA client. Host aplikacji .NET.NET Aspire wymaga odwołania do pakietu Aspirepakietu NuGet Hosting.NodeJS i kod musi wywołać AddNodeApp lub AddNpmApp. Te interfejsy API są przydatne do dodawania istniejących aplikacji JavaScript do hosta aplikacji .NET.NET Aspire.

Podczas konfigurowania tajemnic i przekazywania zmiennych środowiskowych do aplikacji opartych na JavaScript, niezależnie od tego, czy są to aplikacje client, czy server, powinny być użyte parametry. Aby uzyskać więcej informacji, zapoznaj się z .NET.NET Aspire: Parametry zewnętrzne — tajne.

Korzystanie z zestawu SDK języka JavaScript OpenTelemetry

Aby wyeksportować dzienniki OpenTelemetry, ślady i metryki z aplikacji Node.jsserver, należy użyć JavaScript SDK OpenTelemetry.

Kompletny przykład aplikacji Node.jsserver korzystających z zestawu SDK języka JavaScript OpenTelemetry można znaleźć na stronie przykładów kodu : .NET AspireNode.js przykładowej strony. Rozważmy plik instrumentation.js przykładu, który pokazuje, jak skonfigurować zestaw SDK języka JavaScript OpenTelemetry do eksportowania dzienników, śladów i metryk:

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();
}

Napiwek

Aby skonfigurować ustawienia CORS OTEL dla pulpitu nawigacyjnego .NET.NET Aspire, zobacz stronę ustawień CORS OTEL pulpitu nawigacyjnego .NET.NET Aspire.

Streszczenie

Chociaż istnieje kilka zagadnień wykraczających poza zakres tego artykułu, przedstawiono sposób tworzenia projektów .NET Aspire korzystających z Node.js i Menedżera pakietów węzłów (npm). Nauczyłeś się również, jak używać interfejsów API AddNpmApp do hostowania aplikacji Node.js oraz aplikacji wykonywanych z pakietu . Plikjson, odpowiednio. Na koniec przedstawiono sposób używania interfejsu wiersza polecenia npm do tworzenia Angular, Reacti Vueclient aplikacji oraz konfigurowania ich do uruchamiania na różnych portach.

Zobacz też