이 세션에서는 Blazor 프론트엔드 웹 앱의 JS Interop 기능을 활용해 React 기반의 UI 컴포넌트를 통합해 보겠습니다.
GitHub Codespaces 또는 Visual Studio Code 환경에서 작업하는 것을 기준으로 합니다.
node.js 18+ 버전을 사용하고 있는지 확인해 주세요.
-
터미널을 열고 아래 명령어를 차례로 실행시켜 리포지토리의 루트 디렉토리로 이동합니다.
# GitHub Codespaces REPOSITORY_ROOT=$CODESPACE_VSCODE_FOLDER cd $REPOSITORY_ROOT # bash/zsh REPOSITORY_ROOT=$(git rev-parse --show-toplevel) cd $REPOSITORY_ROOT # PowerShell $REPOSITORY_ROOT = git rev-parse --show-toplevel cd $REPOSITORY_ROOT
세이브 포인트에서 가져온 프로젝트를 사용하려면 아래 명령어를 차례로 실행시켜 프로젝트를 복원합니다.
# bash/zsh mkdir -p workshop && cp -a save-points/session-05/. workshop/ cd workshop dotnet restore && dotnet build # PowerShell New-Item -Type Directory -Path workshop -Force && Copy-Item -Path ./save-points/session-05/* -Destination ./workshop -Recurse -Force cd workshop dotnet restore && dotnet build
-
AspireYouTubeSummariser.WebApp
프로젝트에JSInterop
디렉토리를 생성합니다.# bash/zsh mkdir -p $REPOSITORY_ROOT/workshop/AspireYouTubeSummariser.WebApp/JSInterop cd $REPOSITORY_ROOT/workshop/AspireYouTubeSummariser.WebApp/JSInterop # PowerShell New-Item -Type Directory -Path $REPOSITORY_ROOT/workshop/AspireYouTubeSummariser.WebApp/JSInterop -Force cd $REPOSITORY_ROOT/workshop/AspireYouTubeSummariser.WebApp/JSInterop
-
아래 명령어를 실행시켜 node.js 기반의 React 프로젝트를 생성합니다.
npm init
초기화 과정에서 물어보는 아래의 질문에는 엔터키를 눌러 기본값으로 설정하고 지나갑니다.
package name: version: description: entry point: test command: git repository: keywords: author: license:
-
생성된
package.json
파일을 열고 아래 내용으로 수정합니다.{ "scripts": { // 수정 전 "test": "echo \"Error: no test specified\" && exit 1" // 수정 후 "build": "webpack --mode production" }, }
-
아래 명령어를 차례로 실행시켜 npm 패키지를 설치합니다.
npm install --save-dev @babel/core babel-loader webpack webpack-cli npm install @fluentui/react react react-dom
-
webpack.config.js
파일을 생성합니다.# bash/zsh touch webpack.config.js # PowerShell New-Item -Type File -Name webpack.config.js -Force
-
webpack.config.js
파일에 아래 내용을 입력합니다.const path = require("path"); module.exports = { module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader" } } ] }, output: { path: path.resolve(__dirname, '../wwwroot/js'), filename: "bundle.js", library: "YouTube", libraryTarget: "window" } };
-
src
디렉토리를 만들고 그 아래index.js
파일을 생성합니다.# bash/zsh mkdir -p src touch src/index.js # PowerShell New-Item -Type Directory -Name src -Force New-Item -Type File -Name index.js -Path src -Force
-
index.js
파일에 아래와 같이 입력합니다.import { renderProgressBar } from './progressbar'; export function RenderProgressBar() { return renderProgressBar(); }
-
src
디렉토리 밑에progressbar.js
파일을 생성합니다.# bash/zsh touch src/progressbar.js # PowerShell New-Item -Type File -Name progressbar.js -Path src -Force
-
src
디렉토리 밑에progressbar.js
파일을 생성한 후 아래와 같이 입력합니다.import * as React from 'react'; import ReactDOM from 'react-dom'; import { ProgressIndicator } from '@fluentui/react/lib/ProgressIndicator'; export function renderProgressBar(count) { const Progress = () => React.createElement( ProgressIndicator, { 'label': 'Summarising...', 'description': '' }, null ); ReactDOM.render(Progress(), document.getElementById('progressBar')); }
-
AspireYouTubeSummariser.WebApp
프로젝트의AspireYouTubeSummariser.WebApp.csproj
파일을 열어 프로젝트를 빌드할 때 앞서 작성했던 React UI 컴포넌트 역시 동시에 빌드될 수 있게 설정합니다.<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <!-- 추가 --> <JSInteropRoot>JSInterop/</JSInteropRoot> <DefaultItemExcludes>$(DefaultItemExcludes);$(JSInteropRoot)node_modules/**</DefaultItemExcludes> </PropertyGroup> <!-- 추가 --> <ItemGroup> <Content Remove="$(JSInteropRoot)**" /> <None Remove="$(JSInteropRoot)**" /> <None Include="$(JSInteropRoot)**" Exclude="$(JSInteropRoot)node_modules/**" /> </ItemGroup> ... <!-- 추가 --> <Target Name="PublishRunWebpack" AfterTargets="Build"> <!-- As part of publishing, ensure the JS resources are freshly built in production mode --> <Exec WorkingDirectory="$(JSInteropRoot)" Command="npm install" /> <Exec WorkingDirectory="$(JSInteropRoot)" Command="npm run build" /> </Target> </Project>
-
AspireYouTubeSummariser.WebApp
프로젝트의Components/UI
디렉토리에 있는YouTubeSummariserComponent.razor
파일을 열고@inject IApiAppClient ApiApp
라인 아래 아래와 같이 수정합니다.@inject IApiAppClient ApiApp @* 추가 *@ @inject IJSRuntime JSR
-
같은 파일에서 HTML 버튼 아래 아래와 같이 HTML 엘리먼트를 추가합니다.
<div class="row"> <div class="mb-3"> <button type="button" class="btn btn-primary" @onclick="SummariseAsync">Summarise!</button> <button type="button" class="btn btn-secondary" @onclick="ClearAsync">Clear!</button> </div> </div> @* 추가 *@ <div class="row"> <div class="mb-3"> <div id="progressBar" hidden="@summaryCompleted"></div> </div> </div>
-
같은 파일에서
@code
블록을 아래와 같이 수정합니다.@code { ... private string summaryResult = string.Empty; // 추가 private bool summaryCompleted; private async Task SummariseAsync() { // 추가 summaryCompleted = false; await JSR.InvokeVoidAsync("YouTube.RenderProgressBar"); var result = await ApiApp.SummariseAsync(youTubeLinkUrl, videoLanguageCode, summaryLanguageCode); summaryResult = result; // 추가 summaryCompleted = true; } ... }
-
AspireYouTubeSummariser.WebApp
프로젝트의Components
디렉토리에 있는App.razor
파일을 열고<script src="_framework/blazor.web.js"></script>
라인을 찾아 아래와 같이 수정합니다.
<script src="_framework/blazor.web.js"></script>
<!-- 추가 -->
<script src="js/bundle.js"></script>
-
AspireYouTubeSummariser.AppHost
프로젝트의appsettings.Development.json
파일에 세션 05: Azure 배포 - Azure Kubernetes Service에서 등록한 OpenAI 정보를 다시 입력합니다."OpenAI": { "Endpoint": "{{ Azure OpenAI Proxy Service Endpoint }}", "ApiKey": "{{ Azure OpenAI Proxy Service Access Code }}", "DeploymentName": "{{ Azure OpenAI Proxy Service Deployment Name }}" }
중요:
appsettings.json
파일에 추가한 Azure OpenAI 서비스의 값들은 절대로 GitHub에 커밋하지 마세요. 대신appsettings.Development.json
파일에 추가하세요..gitignore
파일에 이미appsettings.Development.json
파일에 대한 제외 옵션이 추가되어 있습니다. -
Solution Explorer에서
AspireYouTubeSummariser.AppHost
프로젝트를 선택하고 마우스 오른쪽 버튼을 눌러 디버깅 모드로 실행합니다.또는 아래 명령어를 차례로 실행시켜 앱을 실행합니다.
cd $REPOSITORY_ROOT/workshop dotnet watch run --project AspireYouTubeSummariser.AppHost
-
대시보드 페이지를 열고 Blazor 프론트엔드 웹 앱을 실행시킵니다.
-
홈페이지에서 YouTube 링크를 입력하고
Summarise
버튼을 클릭합니다.YouTube 링크는 무엇이든 상관 없습니다. 여기서는 https://youtu.be/NN4Zzp-vOrU 링크를 사용합니다. 혹시나 토큰 길이 관련 에러가 나오는 경우에는 30분 이하의 짧은 동영상을 사용해 보세요.
-
Summarising...
이라는 텍스트와 함께 진행 상태바가 움직이는 것을 확인합니다. -
디버깅 모드를 종료합니다. 또는 터미널 창에서 웹 앱을 실행시켰을 경우
CTRL
+C
키를 눌러 실행을 중지합니다.
-
아래 명령어를 차례로 실행시켜 배포 환경을 준비합니다.
# bash/zsh cd $REPOSITORY_ROOT/workshop AZURE_ENV_NAME="{{ GITHUB_ID }}" azd init -e $AZURE_ENV_NAME # PowerShell cd $REPOSITORY_ROOT/workshop $AZURE_ENV_NAME = "{{ GITHUB_ID }}" azd init -e $AZURE_ENV_NAME
중요:
{{ GITHUB_ID }}
는 자신의 GitHub 아이디로 변경해야 합니다. 예를 들어 GitHub 아이디가Azure-Samples
라면{{ GITHUB_ID }}
를Azure-Samples
로 변경하세요. -
아래 명령어를 실행시켜 앱을 배포합니다.
azd up
-
어떤 Azure 구독을 사용할 것인지 물어봅니다. 사용할 구독을 선택합니다.
-
어느 지역에 배포할 것인지 물어봅니다. 아무 지역이나 선택해도 되지만, 여기서는
Korea Central
을 선택합니다. -
배포가 끝난 후
webapp
컨테이너 앱을 실행시켜 홈페이지에서 YouTube 링크를 입력하고Summarise
버튼을 클릭합니다.YouTube 링크는 무엇이든 상관 없습니다. 여기서는 https://youtu.be/NN4Zzp-vOrU 링크를 사용합니다. 혹시나 토큰 길이 관련 에러가 나오는 경우에는 30분 이하의 짧은 동영상을 사용해 보세요.
-
Summarising...
이라는 텍스트와 함께 진행 상태바가 움직이는 것을 확인합니다.
-
아래 명령어를 통해 배포한 앱을 삭제합니다.
azd down --purge --force
축하합니다! Blazor 프론트엔드 웹 앱에 JS Interop 기능을 통해 React 기반의 UI 컴포넌트를 통합하는 작업이 끝났습니다.
(추가 세션) 이제 세션 07: Semantic Kernel 앱 개발으로 넘어가세요.