Orchestrare le app Node.js in .NET Aspire

Questo articolo illustra come usare app Node.js e Node Package Manager (npm) in un progetto di .NET.NET Aspire. L'app di esempio in questo articolo dimostra le esperienze client Angular, Reacte Vue. Le API .NET.NET Aspire seguenti esistono per supportare questi scenari e fanno parte del pacchetto NuGet Aspire.Hosting.NodeJS.

La differenza tra queste due API è che la prima viene usata per ospitare app Node.js, mentre l'ultima è utilizzata per ospitare app che vengono eseguite dalla sezione scripts di un file package.json e il comando corrispondente npm run <script-name>.

Suggerimento

Il codice sorgente di esempio per questo articolo è disponibile in GitHube sono disponibili informazioni dettagliate nella pagina esempi di codice : .NET Aspire con Angular, React e Vue.

Importante

Anche se questo articolo è incentrato sui bit front-end Single-Page app (SPA), è disponibile un esempio aggiuntivo Node.js negli esempi di codice : .NET AspireNode.js pagina di esempio, che illustra come usare Node.js come un'app server con express.

Prerequisiti

Per usare .NET.NET Aspire, è necessario che il codice seguente sia installato in locale:

Per altre informazioni, vedere .NET.NET Aspire configurazione e strumentie .NET.NET Aspire SDK.

Inoltre, è necessario installare Node.js nel computer. L'app di esempio in questo articolo è stata compilata con Node.js versione 20.12.2 e npm versione 10.5.1. Per verificare le versioni di Node.js e npm, eseguire i comandi seguenti:

node --version
npm --version

Per scaricare Node.js (incluso npm), vedere la pagina di download Node.js.

Clonare il codice sorgente di esempio

Per clonare il codice sorgente di esempio da GitHub, eseguire il comando seguente:

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

Dopo aver clonato il repository, passare alla cartella samples/AspireWithJavaScript:

cd samples/AspireWithJavaScript

Da questa directory sono disponibili sei directory figlio descritte nell'elenco seguente:

  • AspireJavaScript.Angular: un'app Angular che usa l'API previsioni meteo e visualizza i dati in una tabella.
  • AspireJavaScript.AppHost: un progetto di .NET.NET Aspire che orchestra le altre app in questo esempio. Per altre informazioni, vedere panoramica dell'orchestrazione .NET.NET Aspire.
  • AspireJavaScript.MinimalApi: UN'API HTTP che restituisce dati di previsione meteo generati in modo casuale.
  • AspireJavaScript.React: un'app React che usa l'API previsioni meteo e visualizza i dati in una tabella.
  • AspireJavaScript.ServiceDefaults: progetto condiviso predefinito per i progetti .NET.NET Aspire. Per altre informazioni, vedere impostazioni predefinite del servizio .NET.NET Aspire.
  • AspireJavaScript.Vue: un'app Vue che usa l'API previsioni meteo e visualizza i dati in una tabella.

Installare le dipendenze client

L'app di esempio illustra come usare le app client JavaScript basate su Node.js. Ogni app client è stata scritta utilizzando un modello di comando npm create o manualmente. La tabella seguente elenca i comandi modello usati per creare ogni app client, insieme alla porta predefinita:

Tipo di app Comando Crea modello Porta predefinita
Angular npm create @angular@latest 4200
React Non è stato usato un modello. PORT env var
Vue npm create vue@latest 5173

Suggerimento

Non è necessario eseguire nessuno di questi comandi, perché l'app di esempio include già i client. Si tratta invece di un punto di riferimento da cui sono stati creati i clienti. Per altre informazioni, vedere npm-init.

Per eseguire l'app, è prima necessario installare le dipendenze per ogni client. A tale scopo, passare a ogni cartella client ed eseguire npm install (o il comando alias di installazione npm i).

Installare le dipendenze Angular

npm i ./AspireJavaScript.Angular/

Per ulteriori informazioni sull'app Angular, consultare per esplorare il client Angular.

Installare le dipendenze React

npm i ./AspireJavaScript.React/

Per altre informazioni sull'app React, vedere esplorare il client React.

Installare le dipendenze Vue

npm i ./AspireJavaScript.Vue/

Per ulteriori informazioni sull'app Vue, consultare la sezione ed esplorare il client Vue.

Eseguire l'app di esempio

Per eseguire l'app di esempio, eseguire il comando dotnet run con l'host dell'app dell'agente di orchestrazione AspireJavaScript.AppHost.csproj come switch --project.

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

Il dashboard .NET.NET Aspire viene avviato nel browser predefinito e ogni endpoint dell'app client viene visualizzato nella colonna Endpoint della pagina Risorse. L'immagine seguente illustra il dashboard per questa app di esempio:

.NET.NET Aspire dashboard con più app client JavaScript.

L'endpoint di servizio weatherapi si risolve in una pagina Swagger UI che documenta l'API HTTP. Ogni app client usa questo servizio per visualizzare i dati delle previsioni meteo. È possibile visualizzare ogni app client passando all'endpoint corrispondente nel dashboard di .NET.NET Aspire. Gli screenshot e le modifiche apportate dal punto di partenza del modello sono descritti in dettaglio nelle sezioni seguenti.

Nella stessa sessione del terminale usata per eseguire l'app premere CTRL + C per arrestare l'app.

Esplora l'host dell'app

Per aiutarti a comprendere come viene orchestrata ogni risorsa dell'app client, puoi fare riferimento al progetto host dell'app. L'host dell'app richiede il pacchetto NuGet Aspire.Hosting.NodeJS per ospitare le app 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>

Il file di progetto definisce anche una destinazione di compilazione che garantisce l'installazione delle dipendenze npm prima della compilazione dell'host dell'app. Il codice host dell'app (Program.cs) dichiara le risorse dell'app client usando l'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();

Il codice precedente:

  • Crea un DistributedApplicationBuilder.
  • Aggiunge il servizio "weatherapi" come progetto all'app host.
    • Contrassegna gli endpoint HTTP come esterni.
  • Con riferimento al servizio "weatherapi", aggiunge le applicazioni client "angular", "react" e "vue" come applicazioni npm.
    • Ogni app client è configurata per l'esecuzione su una porta contenitore diversa e usa la variabile di ambiente PORT per determinare la porta.
    • Tutte le app client si basano anche su un Dockerfile per costruire l'immagine del loro container e sono configurate per esprimersi nel manifest di pubblicazione come container derivante dall'API PublishAsDockerFile.

Per altre informazioni sul networking a ciclo interno, vedere .NET.NET Aspire panoramica del networking a ciclo interno. Per altre informazioni sulla distribuzione di app, vedere .NET.NET Aspire formato manifesto per i generatori di strumenti di distribuzione.

Quando l'host dell'app orchestra l'avvio di ogni app client, usa il comando npm run start. Questo comando viene definito nella sezione scripts del file package.json per ogni app client. Lo script start viene usato per avviare l'app client sulla porta specificata. Ogni app client si basa su un proxy per richiedere il servizio "weatherapi".

Il proxy è configurato in:

  • File di proxy.conf.js per il client Angular.
  • File di webpack.config.js per il client React.
  • File di vite.config.ts per il client Vue.

Esplorare il client Angular

Sono state apportate diverse modifiche chiave dal modello di Angular originale. Il primo è l'aggiunta di un file proxy.conf.js. Questo file viene usato per instradare le richieste tramite proxy dal client Angular al servizio "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": "",
    },
  },
};

L'host dell'app .NET.NET Aspire imposta la variabile di ambiente services__weatherapi__http__0, usata per risolvere l'endpoint del servizio "weatherapi". La configurazione precedente instrada le richieste HTTP che iniziano con /api verso l'URL di destinazione specificato nella variabile d'ambiente.

Il secondo aggiornamento riguarda il file package.json. Questo file viene usato per configurare il client Angular per l'esecuzione su una porta diversa rispetto alla porta predefinita. A tale scopo, usare la variabile di ambiente PORT e il pacchetto npm run-script-os per impostare la porta.

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

La sezione scripts del file di package.json viene usata per definire lo script di start. Questo script viene usato dal comando npm start per avviare l'app client Angular. Lo script start è configurato per utilizzare il pacchetto run-script-os per impostare la porta, delegando al comando ng serve il passaggio del commutatore --port adeguato in base alla sintassi del sistema operativo in uso.

Per effettuare chiamate HTTP al servizio "weatherapi", l'app client Angular deve essere configurata per fornire il AngularHttpClient per l'inserimento delle dipendenze. Questo viene ottenuto usando la funzione helper provideHttpClient durante la configurazione dell'applicazione nel file 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()
  ]
};

Infine, l'app client Angular deve chiamare l'endpoint /api/WeatherForecast per recuperare i dati delle previsioni meteo. Sono disponibili diversi aggiornamenti HTML, CSS e TypeScript, tutti apportati ai file seguenti:

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 app in esecuzione

Per visualizzare l'app client Angular, passare all'endpoint "angular" nel dashboard .NET Aspire. L'immagine seguente illustra l'app client Angular:

Angular applicazione client con dati meteorologici falsi visualizzati in formato tabella.

Esplorare il client React

L'app React non è stata scritta usando un modello e invece è stata scritta manualmente. Il codice sorgente completo è disponibile nel repository dotnet/aspire-samples. Alcuni dei punti chiave di interesse sono disponibili nel file 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;

La funzione App è il punto di ingresso per l'app client React. Usa gli hook useState e useEffect per gestire lo stato dei dati delle previsioni meteo. L'API fetch viene usata per effettuare una richiesta HTTP all'endpoint /api/WeatherForecast. La risposta viene quindi convertita in JSON e impostata come stato dei dati delle previsioni meteo.

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

Il codice precedente definisce il module.exports come indicato di seguito:

  • La proprietà entry è impostata sul file src/ index.js.
  • Il devServer utilizza un proxy per inoltrare le richieste al servizio "weatherapi", imposta la porta sulla variabile di ambiente PORT e permette l'accesso a tutti gli host.
  • Il output restituisce una cartella dist con un filebundle.js.
  • Il plugins imposta il file src/index.html come modello ed espone il file favicon.ico.

Gli aggiornamenti finali sono relativi ai file seguenti:

React app in esecuzione

Per visualizzare l'app client React, passare all'endpoint "react" nel dashboard .NET Aspire. L'immagine seguente illustra l'app client React:

React app client con dati meteo falsi visualizzati come tabella.

Esplorare il client Vue

Sono state apportate diverse modifiche chiave dal modello di Vue originale. Gli aggiornamenti principali sono stati l'aggiunta della chiamata fetch nel file TheWelcome.vue per recuperare i dati delle previsioni meteo dall'endpoint /api/WeatherForecast. Il frammento di codice seguente illustra la chiamata 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>

Poiché l'integrazione TheWelcome è mounted, chiama l'endpoint /api/weatherforecast per recuperare i dati delle previsioni meteorologiche. La risposta viene quindi impostata come proprietà di dati forecasts. Per impostare la porta del server, l'app client Vue usa la variabile di ambiente PORT. A questo scopo, aggiornare il file 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
      }
    }
  }
})

Inoltre, la configurazione Vite specifica la proprietà server.proxy per inoltrare le richieste al servizio "weatherapi". A tale scopo, usare la variabile di ambiente services__weatherapi__http__0, impostata dall'host dell'app .NET.NET Aspire.

L'aggiornamento del modello finale viene eseguito al file TheWelcome.vue. Questo file chiama l'endpoint /api/WeatherForecast per recuperare i dati delle previsioni meteo e visualizza i dati in una tabella. Comprende aggiornamenti CSS, HTML e TypeScript.

Vue app in esecuzione

Per visualizzare l'app client Vue, passare all'endpoint "vue" nel dashboard .NET Aspire. L'immagine seguente illustra l'app client Vue:

Vue app client con dati meteo falsi visualizzati come tabella.

Considerazioni sulla distribuzione

Il codice sorgente di esempio per questo articolo è progettato per l'esecuzione in locale. Ogni app client viene distribuita come immagine container. Il Dockerfile per ogni app client viene usato per compilare l'immagine del contenitore. Ogni Dockerfile è identico, usando una compilazione a più fasi per creare un'immagine del contenitore pronta per la produzione.

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

Le app client sono attualmente configurate per funzionare come vere app SPA (Single Page Application) e non sono configurate per funzionare in modalità SSR (Server-Side Rendering). Si trovano dietro nginx, che viene usato per gestire i file statici. Usano un file default.conf.template per configurare nginx alle richieste proxy all'app client.

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

Considerazioni sull'applicazione server Node.js

Anche se questo articolo è incentrato sulle app client, potrebbero essere presenti scenari in cui è necessario ospitare un'app server Node.js. Per ospitare un'app server Node.js, è necessaria la stessa semantica di un'applicazione cliente a pagina singola. L'host dell'app .NET.NET Aspire richiede un riferimento al pacchetto Aspire.Hosting.NodeJS NuGet e il codice deve chiamare AddNodeApp o AddNpmApp. Queste API sono utili per aggiungere app JavaScript esistenti all'host dell'app .NET.NET Aspire.

Quando si configurano i segreti e si passano variabili di ambiente alle app basate su JavaScript, sia che si tratti di app client o server, usare i parametri. Per altre informazioni, vedere .NET.NET Aspire: Parametri esterni: segreti.

Usare lo OpenTelemetry JavaScript SDK

Per esportare OpenTelemetry log, tracce e metriche da un'app server Node.js, usare OpenTelemetry JavaScript SDK.

Per un esempio completo di un'app server Node.js usando l'SDK JavaScript OpenTelemetry, è possibile fare riferimento alla pagina esempi di codice : .NET AspireNode.js di esempio. Considerare il file di esempio instrumentation.js, che illustra come configurare lo OpenTelemetry JavaScript SDK per esportare i log, le tracce e le metriche.

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

Suggerimento

Per configurare le impostazioni CORS del dashboard .NET.NET Aspire OTEL, vedere la pagina delle impostazioni CORS del dashboard .NET.NET Aspire.

Sommario

Anche se vi sono diverse considerazioni che vanno oltre l'ambito di questo articolo, hai appreso come sviluppare progetti .NET Aspire che utilizzano Node.js e Node Package Manager (npm). Si è anche appreso come usare le API AddNpmApp per ospitare rispettivamente app e app Node.js eseguite da un file package.json. Infine, hai imparato come usare l'interfaccia a riga di comando di npm per creare app client Angular, Reacte Vue e come configurarle per il funzionamento su porte diverse.

Vedere anche