ASP.NET Core의 SPA(단일 페이지 앱) 개요
참고 항목
이 문서의 최신 버전은 아닙니다. 현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.
Important
이 정보는 상업적으로 출시되기 전에 실질적으로 수정될 수 있는 시험판 제품과 관련이 있습니다. Microsoft는 여기에 제공된 정보에 대해 어떠한 명시적, 또는 묵시적인 보증을 하지 않습니다.
현재 릴리스는 이 문서의 .NET 8 버전을 참조 하세요.
Visual Studio는 ASP.NET Core 백 엔드가 있는 Angular, React 및 Vue와 같은 JavaScript 프레임워크를 기반으로 SPA(단일 페이지 앱)를 만들기 위한 프로젝트 템플릿을 제공합니다. 다음 템플릿:
- 프런트 엔드 프로젝트와 백 엔드 프로젝트를 사용하여 Visual Studio 솔루션을 만듭니다.
- 프런트 엔드에는 JavaScript 및 TypeScript(.esproj)에 Visual Studio 프로젝트 형식을 사용합니다.
- 백 엔드에 ASP.NET Core 프로젝트를 사용합니다.
Visual Studio 템플릿을 사용하여 만든 프로젝트는 Windows, Linux 및 macOS의 명령줄에서 실행할 수 있습니다. 앱을 실행하려면 서버 프로젝트를 실행하는 데 사용합니다 dotnet run --launch-profile https
. 서버 프로젝트를 실행하면 프런트 엔드 JavaScript 개발 서버가 자동으로 시작됩니다. https
현재 시작 프로필이 필요합니다.
Visual Studio 자습서
시작하려면 Visual Studio 설명서의 자습서 중 하나를 따르세요.
자세한 내용은 Visual Studio의 JavaScript 및 TypeScript를 참조 하세요.
ASP.NET 핵심 SPA 템플릿
Visual Studio에는 JavaScript 또는 TypeScript 프런트 엔드를 사용하여 ASP.NET Core 앱을 빌드하기 위한 템플릿이 포함되어 있습니다. 이러한 템플릿은 ASP.NET 및 웹 개발 워크로드가 설치된 Visual Studio 2022 버전 17.8 이상에서 사용할 수 있습니다.
JavaScript 또는 TypeScript 프런트 엔드를 사용하여 ASP.NET Core 앱을 빌드하기 위한 Visual Studio 템플릿은 다음과 같은 이점을 제공합니다.
- 프런트 엔드 및 백 엔드에 대한 프로젝트 분리를 정리합니다.
- 최신 프런트 엔드 프레임워크 버전을 최신 상태로 유지합니다.
- Vite와 같은 최신 프런트 엔드 프레임워크 명령줄 도구와 통합합니다.
- JavaScript 및 TypeScript 모두에 대한 템플릿입니다(Angular의 경우 TypeScript만 해당).
- 다양한 JavaScript 및 TypeScript 코드 편집 환경.
- JavaScript 빌드 도구를 .NET 빌드와 통합합니다.
- npm 종속성 관리 UI.
- Visual Studio Code 디버깅 및 시작 구성과 호환됩니다.
- JavaScript 테스트 프레임워크를 사용하여 테스트 탐색기에서 프런트 엔드 단위 테스트를 실행합니다.
레거시 ASP.NET 핵심 SPA 템플릿
이전 버전의 .NET SDK에는 ASP.NET Core를 사용하여 SPA 앱을 빌드하기 위한 레거시 템플릿이 포함되어 있습니다. 이러한 이전 템플릿에 대한 설명서는 spa 개요의 ASP.NET Core 7.0 버전 및 Angular 및 React 문서를 참조하세요.
단일 페이지 애플리케이션 템플릿의 아키텍처
Angular 및 React에 대한 SPA(단일 페이지 애플리케이션) 템플릿은 .NET 백 엔드 서버 내에서 호스트되는 Angular 및 React 앱을 개발하는 기능을 제공합니다.
게시 시 Angular 및 React 앱의 파일이 wwwroot
폴더에 복사되고 정적 파일 미들웨어를 통해 제공됩니다.
대체 경로는 HTTP 404(찾을 수 없음)를 반환하는 대신 백 엔드에 알 수 없는 요청을 처리하고 SPA에 대해 index.html
를 제공합니다.
개발하는 동안 앱은 프런트 엔드 프록시를 사용하도록 구성됩니다. React 및 Angular 동일한 프런트 엔드 프록시를 사용합니다.
앱이 시작되면 브라우저에서 index.html
페이지가 열립니다. 개발에서만 사용하도록 설정된 특수 미들웨어:
- 들어오는 요청을 가로챌 수 있습니다.
- 프록시가 실행 중인지 여부를 확인합니다.
- 프록시가 실행 중이거나 프록시의 새 인스턴스를 시작하는 경우 프록시의 URL로 리디렉션됩니다.
- 프록시가 작동 중이고 브라우저가 리디렉션될 때까지 몇 초마다 자동으로 새로 고치는 브라우저에 페이지를 반환합니다.
ASP.NET Core SPA 템플릿이 제공하는 주요 이점은 다음과 같습니다.
- 아직 실행되지 않은 경우 프록시를 시작합니다.
- HTTPS 설정.
- 백 엔드 ASP.NET Core 서버에 프록시할 일부 요청을 구성합니다.
브라우저가 백 엔드 엔드포인트에 대한 요청을 보내는 경우(예: 템플릿 내의 /weatherforecast
). SPA 프록시는 요청을 수신하고 투명하게 서버로 다시 보냅니다. 서버가 응답하고 SPA 프록시가 요청을 브라우저로 다시 보냅니다.
게시된 단일 페이지 앱
앱이 게시되면 SPA는 wwwroot
폴더의 파일 컬렉션이 됩니다.
앱을 제공하는 데 필요한 런타임 구성 요소는 없습니다.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.MapControllerRoute(
name: "default",
pattern: "{controller}/{action=Index}/{id?}");
app.MapFallbackToFile("index.html");
app.Run();
이전 템플릿에서 생성된 Program.cs
파일:
app.
UseStaticFiles를 통해 파일을 제공 할 수 있습니다.app.
MapFallbackToFile("index.html")
을 사용하면 서버에서 수신하는 알 수 없는 요청에 대해 기본 문서를 제공할 수 있습니다.
dotnet publish를 사용하여 앱을 게시할 때, csproj
파일의 다음 작업은 npm restore
가 실행되고 적절한 npm 스크립트가 실행되어 프로덕션 아티팩트를 생성하도록 합니다.
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
단일 페이지 앱 개발
프로젝트 파일은 개발 중에 앱의 동작을 제어하는 몇 가지 속성을 정의합니다.
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<TypeScriptCompileBlocked>true</TypeScriptCompileBlocked>
<TypeScriptToolsVersion>Latest</TypeScriptToolsVersion>
<IsPackable>false</IsPackable>
<SpaRoot>ClientApp\</SpaRoot>
<DefaultItemExcludes>$(DefaultItemExcludes);$(SpaRoot)node_modules\**</DefaultItemExcludes>
<SpaProxyServerUrl>https://localhost:44414</SpaProxyServerUrl>
<SpaProxyLaunchCommand>npm start</SpaProxyLaunchCommand>
<ImplicitUsings>enable</ImplicitUsings>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.SpaProxy" Version="7.0.1" />
</ItemGroup>
<ItemGroup>
<!-- Don't publish the SPA source files, but do show them in the project files list -->
<Content Remove="$(SpaRoot)**" />
<None Remove="$(SpaRoot)**" />
<None Include="$(SpaRoot)**" Exclude="$(SpaRoot)node_modules\**" />
</ItemGroup>
<Target Name="DebugEnsureNodeEnv" BeforeTargets="Build" Condition=" '$(Configuration)' == 'Debug' And !Exists('$(SpaRoot)node_modules') ">
<!-- Ensure Node.js is installed -->
<Exec Command="node --version" ContinueOnError="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
<Error Condition="'$(ErrorCode)' != '0'" Text="Node.js is required to build and run this project. To continue, please install Node.js from https://nodejs.org/, and then restart your command prompt or IDE." />
<Message Importance="high" Text="Restoring dependencies using 'npm'. This may take several minutes..." />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
</Target>
<Target Name="PublishRunWebpack" AfterTargets="ComputeFilesToPublish">
<!-- As part of publishing, ensure the JS resources are freshly built in production mode -->
<Exec WorkingDirectory="$(SpaRoot)" Command="npm install" />
<Exec WorkingDirectory="$(SpaRoot)" Command="npm run build" />
<!-- Include the newly-built files in the publish output -->
<ItemGroup>
<DistFiles Include="$(SpaRoot)build\**" />
<ResolvedFileToPublish Include="@(DistFiles->'%(FullPath)')" Exclude="@(ResolvedFileToPublish)">
<RelativePath>wwwroot\%(RecursiveDir)%(FileName)%(Extension)</RelativePath>
<CopyToPublishDirectory>PreserveNewest</CopyToPublishDirectory>
<ExcludeFromSingleFile>true</ExcludeFromSingleFile>
</ResolvedFileToPublish>
</ItemGroup>
</Target>
</Project>
SpaProxyServerUrl
: 서버에서 SPA 프록시가 실행될 것으로 예상되는 URL을 제어합니다. URL은 다음과 같습니다.- 서버는 프록시를 시작한 후 ping을 실행하여 준비가 되었는지 확인합니다.
- 성공적인 응답 후에 브라우저를 리디렉션하는 위치입니다.
SpaProxyLaunchCommand
: 서버가 프록시가 실행되고 있지 않음을 감지할 때 SPA 프록시를 시작하는 데 사용하는 명령입니다.
패키지 Microsoft.AspNetCore.SpaProxy
는 프록시를 검색하고 브라우저를 리디렉션하는 이전 논리를 담당합니다.
Properties/launchSettings.json
에 정의된 호스팅 시작 어셈블리는 개발 중에 프록시가 실행 중인지 감지하고 그렇지 않은 경우 시작하는 데 필요한 구성 요소를 자동으로 추가하는 데 사용됩니다.
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:51783",
"sslPort": 44329
}
},
"profiles": {
"MyReact": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:7145;http://localhost:5273",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
},
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development",
"ASPNETCORE_HOSTINGSTARTUPASSEMBLIES": "Microsoft.AspNetCore.SpaProxy"
}
}
}
}
클라이언트 앱에 대한 설정
이 설정은 앱이 사용하는 프런트 엔드 프레임워크와 관련이 있지만 구성의 많은 측면은 비슷합니다.
Angular 설정
템플릿 생성 ClientApp/package.json
파일:
{
"name": "myangular",
"version": "0.0.0",
"scripts": {
"ng": "ng",
"prestart": "node aspnetcore-https",
"start": "run-script-os",
"start:windows": "ng serve --port 44483 --ssl --ssl-cert \"%APPDATA%\\ASP.NET\\https\\%npm_package_name%.pem\" --ssl-key \"%APPDATA%\\ASP.NET\\https\\%npm_package_name%.key\"",
"start:default": "ng serve --port 44483 --ssl --ssl-cert \"$HOME/.aspnet/https/${npm_package_name}.pem\" --ssl-key \"$HOME/.aspnet/https/${npm_package_name}.key\"",
"build": "ng build",
"build:ssr": "ng run MyAngular:server:dev",
"watch": "ng build --watch --configuration development",
"test": "ng test"
},
"private": true,
"dependencies": {
"@angular/animations": "^14.1.3",
"@angular/common": "^14.1.3",
"@angular/compiler": "^14.1.3",
"@angular/core": "^14.1.3",
"@angular/forms": "^14.1.3",
"@angular/platform-browser": "^14.1.3",
"@angular/platform-browser-dynamic": "^14.1.3",
"@angular/platform-server": "^14.1.3",
"@angular/router": "^14.1.3",
"bootstrap": "^5.2.0",
"jquery": "^3.6.0",
"oidc-client": "^1.11.5",
"popper.js": "^1.16.0",
"run-script-os": "^1.1.6",
"rxjs": "~7.5.6",
"tslib": "^2.4.0",
"zone.js": "~0.11.8"
},
"devDependencies": {
"@angular-devkit/build-angular": "^14.1.3",
"@angular/cli": "^14.1.3",
"@angular/compiler-cli": "^14.1.3",
"@types/jasmine": "~4.3.0",
"@types/jasminewd2": "~2.0.10",
"@types/node": "^18.7.11",
"jasmine-core": "~4.3.0",
"karma": "~6.4.0",
"karma-chrome-launcher": "~3.1.1",
"karma-coverage": "~2.2.0",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.0.0",
"typescript": "~4.7.4"
},
"overrides": {
"autoprefixer": "10.4.5"
},
"optionalDependencies": {}
}
각 개발 서버를 시작하는 스크립트를 포함합니다.
prestart
스크립트는 SPA 프록시 서버에서 개발 서버 HTTPS 인증서를 사용할 수 있는지 확인하는ClientApp/aspnetcore-https.js
를 호출합니다.start:windows
및start:default
는 다음을 수행합니다.ng serve
를 통해 Angular 개발 서버를 시작합니다.- 포트, HTTPS를 사용하는 옵션, 인증서, 연결된 키에 대한 경로를 제공합니다. 제공 포트 번호는
.csproj
파일에 지정된 포트 번호와 일치합니다.
템플릿에서 생성된 ClientApp/angular.json
파일에는 다음이 포함됩니다.
serve
명령.proxyconfig
다음 강조 표시된 JSON과development
같이 프런트 엔드 프록시를 구성하는 데 사용해야 함을proxy.conf.js
나타내는 구성의 요소입니다.{ "$schema": "./node_modules/@angular/cli/lib/config/schema.json", "version": 1, "newProjectRoot": "projects", "projects": { "MyAngular": { "projectType": "application", "schematics": { "@schematics/angular:application": { "strict": true } }, "root": "", "sourceRoot": "src", "prefix": "app", "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { "progress": false, "outputPath": "dist", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", "allowedCommonJsDependencies": [ "oidc-client" ], "assets": [ "src/assets" ], "styles": [ "node_modules/bootstrap/dist/css/bootstrap.min.css", "src/styles.css" ], "scripts": [] }, "configurations": { "production": { "budgets": [ { "type": "initial", "maximumWarning": "500kb", "maximumError": "1mb" }, { "type": "anyComponentStyle", "maximumWarning": "2kb", "maximumError": "4kb" } ], "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], "outputHashing": "all" }, "development": { "buildOptimizer": false, "optimization": false, "vendorChunk": true, "extractLicenses": false, "sourceMap": true, "namedChunks": true } }, "defaultConfiguration": "production" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "configurations": { "production": { "browserTarget": "MyAngular:build:production" }, "development": { "browserTarget": "MyAngular:build:development", "proxyConfig": "proxy.conf.js" } }, "defaultConfiguration": "development" }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { "browserTarget": "MyAngular:build" } }, "test": { "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "assets": [ "src/assets" ], "styles": [ "src/styles.css" ], "scripts": [] } }, "server": { "builder": "@angular-devkit/build-angular:server", "options": { "outputPath": "dist-server", "main": "src/main.ts", "tsConfig": "tsconfig.server.json" }, "configurations": { "dev": { "optimization": true, "outputHashing": "all", "sourceMap": false, "namedChunks": false, "extractLicenses": true, "vendorChunk": true }, "production": { "optimization": true, "outputHashing": "all", "sourceMap": false, "namedChunks": false, "extractLicenses": true, "vendorChunk": false } } } } } }, "defaultProject": "MyAngular" }
ClientApp/proxy.conf.js
는 서버 백 엔드로 다시 프록시해야 하는 경로를 정의합니다. 일반 옵션 집합은 모두 동일한 프록시를 사용하므로 react 및 angular에 대한 http-proxy-middleware에서 정의됩니다.
ClientApp/proxy.conf.js
에서 강조 표시된 다음 코드는 개발 중에 설정된 환경 변수에 따라 논리를 사용하여 백 엔드가 실행 중인 포트를 확인합니다.
const { env } = require('process');
const target = env.ASPNETCORE_HTTPS_PORTS ? `https://localhost:${env.ASPNETCORE_HTTPS_PORTS}` :
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:51951';
const PROXY_CONFIG = [
{
context: [
"/weatherforecast",
],
target: target,
secure: false,
headers: {
Connection: 'Keep-Alive'
}
}
]
module.exports = PROXY_CONFIG;
React 설정
package.json
스크립트 섹션에는 다음 강조 표시된 코드와 같이 개발 중에 react 앱을 시작하는 다음 스크립트가 포함되어 있습니다.{ "name": "myreact", "version": "0.1.0", "private": true, "dependencies": { "bootstrap": "^5.2.0", "http-proxy-middleware": "^2.0.6", "jquery": "^3.6.0", "merge": "^2.1.1", "oidc-client": "^1.11.5", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-bootstrap": "^0.26.2", "react-router-dom": "^6.3.0", "react-scripts": "^5.0.1", "reactstrap": "^9.1.3", "rimraf": "^3.0.2", "web-vitals": "^2.1.4", "workbox-background-sync": "^6.5.4", "workbox-broadcast-update": "^6.5.4", "workbox-cacheable-response": "^6.5.4", "workbox-core": "^6.5.4", "workbox-expiration": "^6.5.4", "workbox-google-analytics": "^6.5.4", "workbox-navigation-preload": "^6.5.4", "workbox-precaching": "^6.5.4", "workbox-range-requests": "^6.5.4", "workbox-routing": "^6.5.4", "workbox-strategies": "^6.5.4", "workbox-streams": "^6.5.4" }, "devDependencies": { "ajv": "^8.11.0", "cross-env": "^7.0.3", "eslint": "^8.22.0", "eslint-config-react-app": "^7.0.1", "eslint-plugin-flowtype": "^8.0.3", "eslint-plugin-import": "^2.26.0", "eslint-plugin-jsx-a11y": "^6.6.1", "eslint-plugin-react": "^7.30.1", "nan": "^2.16.0", "typescript": "^4.7.4" }, "overrides": { "autoprefixer": "10.4.5" }, "resolutions": { "css-what": "^5.0.1", "nth-check": "^3.0.1" }, "scripts": { "prestart": "node aspnetcore-https && node aspnetcore-react", "start": "rimraf ./build && react-scripts start", "build": "react-scripts build", "test": "cross-env CI=true react-scripts test --env=jsdom", "eject": "react-scripts eject", "lint": "eslint ./src/" }, "eslintConfig": { "extends": [ "react-app" ] }, "browserslist": { "production": [ ">0.2%", "not dead", "not op_mini all" ], "development": [ "last 1 chrome version", "last 1 firefox version", "last 1 safari version" ] } }
prestart
스크립트는 다음을 호출합니다.- 개발 서버 HTTPS 인증서를 SPA 프록시 서버에서 사용할 수 있는지 확인하는 작업을 담당하는
aspnetcore-https.js
. - HTTPS 로컬 개발 인증서를 사용하기 위해 적절한
.env.development.local
파일을 설정하기 위해aspnetcore-react.js
를 호출합니다.aspnetcore-react.js
는 파일에SSL_CRT_FILE=<certificate-path>
및SSL_KEY_FILE=<key-path>
를 추가하여 HTTPS 로컬 개발 인증서를 구성합니다.
- 개발 서버 HTTPS 인증서를 SPA 프록시 서버에서 사용할 수 있는지 확인하는 작업을 담당하는
.env.development
파일은 개발 서버의 포트를 정의하고 HTTPS를 지정합니다.
src/setupProxy.js
는 요청을 백 엔드로 전달하도록 SPA 프록시를 구성합니다. 옵션의 일반 집합은 http-proxy-middleware에 정의되어 있습니다.
ClientApp/src/setupProxy.js
에서 강조 표시된 다음 코드는 개발 중에 설정된 환경 변수에 따라 논리를 사용하여 백 엔드가 실행 중인 포트를 확인합니다.
const { createProxyMiddleware } = require('http-proxy-middleware');
const { env } = require('process');
const target = env.ASPNETCORE_HTTPS_PORTS ? `https://localhost:${env.ASPNETCORE_HTTPS_PORTS}` :
env.ASPNETCORE_URLS ? env.ASPNETCORE_URLS.split(';')[0] : 'http://localhost:51783';
const context = [
"/weatherforecast",
];
const onError = (err, req, resp, target) => {
console.error(`${err.message}`);
}
module.exports = function (app) {
const appProxy = createProxyMiddleware(context, {
target: target,
// Handle errors to prevent the proxy middleware from crashing when
// the ASP NET Core webserver is unavailable
onError: onError,
secure: false,
// Uncomment this line to add support for proxying websockets
//ws: true,
headers: {
Connection: 'Keep-Alive'
}
});
app.use(appProxy);
};
ASP.NET Core SPA 템플릿에서 지원되는 SPA 프레임워크 버전
각 ASP.NET Core 릴리스와 함께 제공되는 SPA 프로젝트 템플릿은 적절한 SPA 프레임워크의 최신 버전을 참조합니다.
SPA 프레임워크는 일반적으로 .NET보다 릴리스 주기가 짧습니다. 두 가지 릴리스 주기로 인해 SPA 프레임워크와 .NET의 지원되는 버전이 동기화되지 않을 수 있습니다. 즉, .NET 주 릴리스가 의존하는 주 SPA 프레임워크 버전은 지원되지 않을 수 있으며, 제공된 SPA 프레임워크의 .NET 버전은 여전히 지원되지 않습니다.
ASP.NET Core SPA 템플릿은 패치 릴리스에서 새 SPA 프레임워크 버전으로 업데이트하여 템플릿을 지원되고 안전한 상태로 유지할 수 있습니다.
추가 리소스
ASP.NET Core