다음을 통해 공유


.NET Aspire에서 Node.js 앱을 조정하다

이 문서에서는 .NET.NET Aspire 프로젝트에서 Node.js 및 노드 패키지 관리자(npm) 앱을 사용하는 방법을 알아봅니다. 이 문서의 샘플 앱은 Angular, ReactVueclient 환경을 보여 줍니다. 다음 .NET.NET Aspire API는 이러한 시나리오를 지원하기 위해 존재하며 Aspire.Hosting.NodeJS NuGet 패키지의 일부입니다.

이러한 두 API의 차이점은 전자가 Node.js 앱을 호스트하는 데 사용되고 후자는 패키지에서 실행되는 앱을 호스트하는 데 사용된다는 점입니다.json 파일의 scripts 섹션과 해당하는 npm run <script-name> 명령입니다.

이 문서의 샘플 소스 코드는 GitHub에서 사용할 수 있으며, 의 코드 샘플( .NET Aspire에는 Angular, React 및 Vue 페이지의 세부 정보 포함)에서 세부 정보를 확인할 수 있습니다.

중요하다

이 문서에서는 SPA(Single-Page App) 프런트엔드 요소에 초점을 맞추고 있지만, 코드 샘플에는 추가 Node.js 샘플이 있으며, .NET AspireNode.js 샘플 페이지에서 Node.js를 Expressserver 앱으로 사용하는 방법을 보여줍니다.

필수 구성 요소

.NET .NET Aspire작업하려면 다음을 로컬에 설치해야 합니다.

자세한 내용은 .NET.NET Aspire 설정 및 도구.NET.NET Aspire SDK참조하세요.

또한 컴퓨터에 Node.js 설치해야 합니다. 이 문서의 샘플 앱은 Node.js 버전 20.12.2 및 npm 버전 10.5.1을 사용하여 빌드되었습니다. Node.js 및 npm 버전을 확인하려면 다음 명령을 실행합니다.

node --version
npm --version

Node.js(npm포함)를 다운로드하려면 Node.js 다운로드 페이지참조하세요.

샘플 소스 코드 복제

GitHub샘플 소스 코드를 복제하려면 다음 명령을 실행합니다.

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

리포지토리를 복제한 후 샘플/AspireWithJavaScript 폴더로 이동합니다.

cd samples/AspireWithJavaScript

이 디렉터리에는 다음 목록에 설명된 6개의 자식 디렉터리가 있습니다.

  • AspireJavaScript.Angular: 일기 예보 API를 사용하고 테이블에 데이터를 표시하는 Angular 앱입니다.
  • AspireJavaScript.AppHost: 이 샘플의 다른 앱을 오케스트레이션하는 .NET.NET Aspire 프로젝트입니다. 자세한 내용은 .NET.NET Aspire 오케스트레이션 개요참조하세요.
  • AspireJavaScript.MinimalApi: 임의로 생성된 일기 예보 데이터를 반환하는 HTTP API입니다.
  • AspireJavaScript.React: 일기 예보 API를 사용하고 테이블에 데이터를 표시하는 React 앱입니다.
  • AspireJavaScript.ServiceDefaults: .NET.NET Aspire 프로젝트의 기본 공유 프로젝트입니다. 자세한 내용은 .NET.NET Aspire 서비스 기본값참조하세요.
  • AspireJavaScript.Vue: 일기 예보 API를 사용하고 테이블에 데이터를 표시하는 Vue 앱입니다.

client 종속성 설치

샘플 앱은 Node.js기반으로 빌드된 JavaScript client 앱을 사용하는 방법을 보여 줍니다. 각 client 앱은 npm create 템플릿 명령을 사용하거나 수동으로 작성되었습니다. 다음 표에서는 기본 포트와 함께 각 client 앱을 만드는 데 사용되는 템플릿 명령을 나열합니다.

앱 유형 템플릿 만들기 명령 기본 포트
Angular npm create @angular@latest 4200
React 템플릿을 사용하지 않았습니다. PORT 환경 변수
Vue npm create vue@latest 5173

샘플 앱에 클라이언트가 이미 포함되어 있으므로 이러한 명령을 실행할 필요가 없습니다. 대신 클라이언트가 만들어진 참조 지점입니다. 자세한 내용은 npm-init을 참고하세요.

앱을 실행하려면 먼저 각 client대한 종속성을 설치해야 합니다. 이렇게 하려면 각 client 폴더로 이동하여 npm install(또는 별칭 npm i설치) 명령을 실행합니다.

Angular 종속성 설치

npm i ./AspireJavaScript.Angular/

앱에 대한 자세한 내용을 보려면 를 탐색하고 을 참조하세요.

React 종속성 설치

npm i ./AspireJavaScript.React/

React 앱에 대한 자세한 내용은 참조하세요. Reactclient탐색하기.

Vue 종속성 설치

npm i ./AspireJavaScript.Vue/

Vue 앱에 대한 자세한 내용은 를 참조하세요. Vue에서client를 탐색해 보세요.

샘플 앱 실행

샘플 앱을 실행하려면 Orchestrator 앱 호스트 AspireJavaScript.AppHost.csproj가 --project 스위치로 지정된 dotnet run 명령을 호출합니다.

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

.NET .NET Aspire 대시보드는 기본 브라우저에서 시작되며, 각 client 앱 엔드포인트는 리소스 페이지의 엔드포인트 열 아래에 표시됩니다. 다음 이미지는 이 샘플 앱의 대시보드를 보여 줍니다.

.NET Aspire 여러 JavaScript client 앱이 있는 대시보드.

weatherapi 서비스 엔드포인트는 HTTP API를 문서화하는 Swagger UI 페이지로 연결됩니다. 각 client 앱은 이 서비스를 사용하여 일기 예보 데이터를 표시합니다. .NET Aspire 대시보드에서 해당 엔드포인트로 이동하여 각 client 앱을 볼 수 있습니다. 해당 스크린샷 및 템플릿 시작점의 수정 내용은 다음 섹션에 자세히 설명되어 있습니다.

앱을 실행하는 데 사용한 것과 동일한 터미널 세션에서 Ctrl + C 눌러 앱을 중지합니다.

앱 호스트 탐색

각 client 앱 리소스가 오케스트레이션되는 방식을 이해하려면 앱 호스트 프로젝트를 참조하십시오. 앱 호스트에는 Aspire.Hosting.NodeJS NuGet 패키지가 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>

또한 프로젝트 파일은 앱 호스트가 빌드되기 전에 npm 종속성이 설치되도록 하는 빌드 대상을 정의합니다. 앱 호스트 코드(Program.cs)는 AddNpmApp(IDistributedApplicationBuilder, String, String, String, String[]) API를 사용하여 client 앱 리소스를 선언합니다.

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

앞의 코드는 다음과 같습니다.

  • DistributedApplicationBuilder만듭니다.
  • "weatherapi" 서비스를 프로젝트로 앱 호스트에 추가합니다.
    • HTTP 엔드포인트를 외부로 표시합니다.
  • "weatherapi" 서비스에 대한 참조를 사용하여 "angular", "react" 및 "vue" client 앱을 npm 앱으로 추가합니다.
    • 각 client 앱은 다른 컨테이너 포트에서 실행되도록 구성되며 PORT 환경 변수를 사용하여 포트를 결정합니다.
    • 또한 모든 client 앱은 Dockerfile 사용하여 컨테이너 이미지를 빌드하고 게시 매니페스트에서 PublishAsDockerFile API의 컨테이너로 자신을 표현하도록 구성됩니다.

내부 루프 네트워킹에 대한 자세한 내용은 내부 루프 네트워킹 개요 참조하세요. 앱 배포에 대한 자세한 내용은 배포 도구 작성기대한 매니페스트 형식을 참조하세요.

앱 호스트는 각 client 앱의 시작을 오케스트레이션할 때 npm run start 명령을 사용합니다. 이 명령은 패키지의 scripts 섹션에서 정의됩니다. 각 client 앱에 대한json 파일입니다. start 스크립트는 지정된 포트에서 client 앱을 시작하는 데 사용됩니다. 각 client 앱은 프록시를 사용하여 "weatherapi" 서비스를 요청합니다.

프록시는 다음에서 구성됩니다.

  • Angular client대한 proxy.conf.js 파일입니다.
  • React client대한 webpack.config.js 파일입니다.
  • vite.config.ts 파일은 Vueclient에 대한 것입니다.

Angular client 탐색하세요

원래 Angular 템플릿에서 몇 가지 주요 수정 사항이 있습니다. 첫 번째는 proxy.conf.js 파일을 추가하는 것입니다. 이 파일은 Angularclient에서 "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": "",
    },
  },
};

.NET .NET Aspire 앱 호스트는 "weatherapi" 서비스 엔드포인트를 확인하는 데 사용되는 services__weatherapi__http__0 환경 변수를 설정합니다. 이전 구성은 환경 변수에 지정된 대상 URL에 대한 /api 시작하는 HTTP 요청을 프록시합니다.

두 번째 업데이트는 패키지입니다.json 파일입니다. 이 파일은 기본 포트와 다른 포트에서 실행되도록 Angularclient 구성하는 데 사용됩니다. 이 작업은 PORT 환경 변수 및 run-script-os npm 패키지를 사용하여 포트를 설정하여 수행됩니다.

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

패키지의 scripts 섹션입니다.json 파일은 start 스크립트를 정의하는 데 사용됩니다. 이 스크립트는 npm start 명령에서 Angularclient 앱을 시작하는 데 사용됩니다. start 스크립트는 run-script-os 패키지를 사용하여 포트를 설정하도록 구성됩니다. 이 포트는 OS에 적합한 구문에 따라 적절한 --port 스위치를 전달하는 ng serve 명령에 위임됩니다.

"weatherapi" 서비스에 대한 HTTP 호출을 하려면 종속성 주입에 대한 AngularHttpClient 제공하도록 Angularclient 앱을 구성해야 합니다. 이 작업은 app.config.ts 파일에서 애플리케이션을 구성하는 동안 provideHttpClient 도우미 함수를 사용하여 수행됩니다.

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

마지막으로 Angularclient 앱은 /api/WeatherForecast 엔드포인트를 호출하여 일기 예보 데이터를 검색해야 합니다. 여러 HTML, CSS 및 TypeScript 업데이트가 있으며 모두 다음 파일에 적용됩니다.

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 앱 실행 중

Angular client 앱을 시각화하려면 .NET Aspire 대시보드에서 "angular" 엔드포인트로 이동합니다. 다음 이미지는 Angularclient 앱을 보여 줍니다.

가짜 예측 날씨 데이터가 테이블로 표시되는 앱 Angularclient.

React client을 탐색

React 앱은 템플릿을 사용하여 작성되지 않고 수동으로 작성되었습니다. 전체 소스 코드는 dotnet/aspire-samples 리포지토리찾을 수 있습니다. 관심 있는 몇 가지 핵심 사항은 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;

App 함수는 Reactclient 앱의 진입점입니다. useStateuseEffect 후크를 사용하여 일기 예보 데이터의 상태를 관리합니다. fetch API는 /api/WeatherForecast 엔드포인트에 대한 HTTP 요청을 만드는 데 사용됩니다. 그런 다음 응답이 JSON 변환되고 일기 예보 데이터의 상태로 설정됩니다.

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

앞의 코드는 다음과 같이 module.exports 정의합니다.

  • entry 속성은 src/index.js 파일로 설정됩니다.
  • devServer 프록시를 사용하여 "weatherapi" 서비스에 요청을 전달하고, 포트를 PORT 환경 변수로 설정하고, 모든 호스트를 허용합니다.
  • outputbundle.js 파일이 있는 dist 폴더를 생성합니다.
  • plugins src/index.html 파일을 템플릿으로 설정하고 favicon.ico 파일을 노출합니다.

최종 업데이트는 다음 파일에 대한 것입니다.

실행 중인 앱 React

React client 앱을 시각화하려면 .NET Aspire 대시보드에서 "react" 엔드포인트로 이동합니다. 다음 이미지는 Reactclient 앱을 보여 줍니다.

가짜 예측 날씨 데이터가 테이블로 표시되는 앱 Reactclient.

Vue client 탐색

원래 Vue 템플릿에서 몇 가지 주요 수정 사항이 있습니다. 기본 업데이트는 엔드포인트에서 일기 예보 데이터를 검색하기 위해, 파일 내의 TheWelcome에 호출을 추가한 것입니다. 다음 코드 조각은 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>

TheWelcome 통합이 mounted/api/weatherforecast 엔드포인트를 호출하여 일기 예보 데이터를 검색합니다. 그런 다음 응답이 forecasts 데이터 속성으로 설정됩니다. server 포트를 설정하기 위해 Vueclient 앱은 PORT 환경 변수를 사용합니다. 이 작업은 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
      }
    }
  }
})

또한 Vite 구성은 "weatherapi" 서비스에 요청을 전달할 server.proxy 속성을 지정합니다. 이는 .NET.NET Aspire 앱 호스트에서 설정하는 services__weatherapi__http__0 환경 변수를 사용하여 수행됩니다.

템플릿의 최종 업데이트는 TheWelcome에 적용됩니다.vue 파일입니다. 이 파일은 /api/WeatherForecast 엔드포인트를 호출하여 일기 예보 데이터를 검색하고 테이블에 데이터를 표시합니다. 여기에는 CSS, HTML 및 TypeScript 업데이트 사항이 포함됩니다.

실행 중인 앱 Vue

Vue client 앱을 시각화하려면 .NET Aspire 대시보드에서 "vue" 엔드포인트로 이동합니다. 다음 이미지는 Vueclient 앱을 보여 줍니다.

가짜 예측 날씨 데이터가 테이블로 표시되는 앱 Vueclient.

배포 고려 사항

이 문서의 샘플 소스 코드는 로컬로 실행되도록 설계되었습니다. 각 client 앱은 컨테이너 이미지로 배포됩니다. 각 client 앱을 위해 Dockerfile이(가) 컨테이너 이미지를 빌드하는 데 사용됩니다. 각 Dockerfile는 동일하며, 다단계 빌드를 사용하여 프로덕션 준비가 완료된 컨테이너 이미지를 만듭니다.

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

client 앱은 현재 실제 SPA 애플리케이션으로 실행되도록 구성되어 있으며, server서버 측 렌더링(SSR) 모드에서 실행되도록 구성되어 있지 않습니다. 정적 파일을 제공하는 데 사용되는 nginx뒤에 배치됩니다. default.conf.template 파일을 사용하여 nginx를 구성하여 요청을 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;
    }
}

Node.js server 앱 고려 사항

이 문서에서는 client 앱을 중시하지만 Node.jsserver 앱을 호스트해야 하는 시나리오가 있을 수 있습니다. SPA client 앱과 동일한 의미 체계를 가지고 Node.jsserver 앱을 호스팅해야 합니다. .NET .NET Aspire 앱 호스트에는 Aspire.Hosting.NodeJS NuGet 패키지에 대한 패키지 참조가 필요하며, 코드는 AddNodeApp 또는 AddNpmApp중 하나를 호출해야 합니다. 이러한 API는 .NET.NET Aspire 앱 호스트에 기존 JavaScript 앱을 추가하는 데 유용합니다.

비밀을 구성하고 환경 변수를 JavaScript 기반 앱에 전달할 때 client 앱이든 server 관계없이 매개 변수를 사용합니다. 자세한 내용은 .NET.NET Aspire: 외부 매개 변수 - 비밀참조하세요.

OpenTelemetry JavaScript SDK 사용

Node.js server 앱에서 OpenTelemetry 로그, 추적 및 메트릭을 내보내려면 OpenTelemetry JavaScript SDK사용합니다.

OpenTelemetry JavaScript SDK를 사용하는 Node.jsserver 앱의 전체 예제는 코드 샘플: .NET AspireNode.js 샘플 페이지를 참조할 수 있습니다. 로그, 추적 및 메트릭을 내보내도록 OpenTelemetry JavaScript SDK를 구성하는 방법을 보여 주는 샘플의 instrumentation.js 파일을 고려합니다.

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

.NET .NET Aspire 대시보드 OTEL CORS 설정을 구성하려면 .NET.NET Aspire 대시보드 OTEL CORS 설정 페이지를 참조하세요.

요약

이 문서의 범위를 벗어나는 몇 가지 고려 사항이 있지만 Node.js 및 노드 패키지 관리자(npm)를 사용하는 .NET Aspire 프로젝트를 빌드하는 방법을 알아보았습니다. 또한 AddNpmApp API를 사용하여 패키지에서 실행되는 Node.js 앱 및 앱을 호스트하는 방법도 알아보았습니다. 각각json 파일입니다. 마지막으로 npm CLI를 사용하여 Angular, React및 Vueclient 앱을 만드는 방법과 다른 포트에서 실행되도록 구성하는 방법을 알아보았습니다.

다음도 참고하세요