연습 - 스토리지 계정을 사용하여 정적 웹 사이트 호스팅

완료됨

이제 API가 클라우드에 배포되었으므로 Tailwind Traders 엔지니어로서 클라이언트 코드를 업데이트하고 배포하여 Azure Functions에 제공되는 SignalR 메시지를 지원해야 합니다.

클라이언트 애플리케이션 업데이트

  1. Visual Studio Code에서 ./start/client/src/index.js를 열고 모든 코드를 바꿔 SignalR 메시지를 수신 대기합니다. 코드는 HTTP 요청을 통해 초기 재고 목록을 가져온 다음 SignalR 연결에서 업데이트를 수신 대기합니다. 주식이 업데이트되면 클라이언트는 UI에서 주가를 업데이트합니다.

    import './style.css';
    import { BACKEND_URL } from './env';
    
    const app = new Vue({
        el: '#app',
        data() {
            return {
                stocks: []
            }
        },
        methods: {
            async getStocks() {
                try {
    
                    const url = `${BACKEND_URL}/api/getStocks`;
                    console.log('Fetching stocks from ', url);
    
                    const response = await fetch(url);
                    if (!response.ok) {
                        throw new Error(`HTTP error! status: ${response.status} - ${response.statusText}`);
                    }
                    app.stocks = await response.json();
                } catch (ex) {
                    console.error(ex);
                }
            }
        },
        created() {
            this.getStocks();
        }
    });
    
    const connect = () => {
    
        const signalR_URL = `${BACKEND_URL}/api`;
        console.log(`Connecting to SignalR...${signalR_URL}`)
    
        const connection = new signalR.HubConnectionBuilder()
                                .withUrl(signalR_URL)
                                .configureLogging(signalR.LogLevel.Information)
                                .build();
    
        connection.onclose(()  => {
            console.log('SignalR connection disconnected');
            setTimeout(() => connect(), 2000);
        });
    
        connection.on('updated', updatedStock => {
            console.log('Stock updated message received', updatedStock);
            const index = app.stocks.findIndex(s => s.id === updatedStock.id);
            console.log(`${updatedStock.symbol} Old price: ${app.stocks[index].price}, New price: ${updatedStock.price}`);
            app.stocks.splice(index, 1, updatedStock);
        });
    
        connection.start().then(() => {
            console.log("SignalR connection established");
        });
    };
    
    connect();
    
  2. ./start/client/index.html을 열고, 앱 ID를 사용하여 현재 DIV 대신 다음 코드를 붙여넣습니다.

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.4/css/bulma.min.css"
            integrity="sha256-8B1OaG0zT7uYA572S2xOxWACq9NXYPQ+U5kHPV1bJN4=" crossorigin="anonymous" />
        <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.8.1/css/all.css"
            integrity="sha384-50oBUHEmvpQ+1lW4y57PTFmhCaXp0ML5d60M1M7uH2+nqUivzIebhndOJK28anvf" crossorigin="anonymous">
        <title>Stock Notifications | Enable automatic updates in a web application using Azure Functions and SignalR</title>
    </head>
    
    <body>
        <div id="app" class="container">
            <h1 class="title">Stocks</h1>
            <div id="stocks">
                <div v-for="stock in stocks" class="stock">
                    <transition name="fade" mode="out-in">
                        <div class="list-item" :key="stock.price">
                            <div class="lead">{{ stock.symbol }}: ${{ stock.price }}</div>
                            <div class="change">Change:
                                <span
                                    :class="{ 'is-up': stock.changeDirection === '+', 'is-down': stock.changeDirection === '-' }">
                                    {{ stock.changeDirection }}{{ stock.change }}
                                </span>
                            </div>
                        </div>
                    </transition>
                </div>
            </div>
        </div>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.10/vue.min.js"
            integrity="sha256-chlNFSVx3TdcQ2Xlw7SvnbLAavAQLO0Y/LBiWX04viY=" crossorigin="anonymous"></script>
        <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/8.0.0/signalr.min.js"></script>
        <script src="bundle.js" type="text/javascript"></script>
    </body>
    </html>
    

    이 태그에는 Vue.js가 주식 데이터 변경에 따라 미묘한 애니메이션을 실행할 수 있도록 하는 전환 요소가 포함되어 있습니다. 주식이 업데이트되면 타일이 페이드 아웃된 후에 빠르게 다시 볼 수 있습니다. 페이지에서 주식 데이터가 가득 차면 사용자는 이러한 방식으로 변경된 주식을 쉽게 확인할 수 있습니다.

  3. SignalR SDK를 포함하려면 bundle.js 참조 바로 위에 다음 스크립트 블록을 추가합니다.

    <script src="https://cdn.jsdelivr.net/npm/@aspnet/signalr@1.0.3/dist/browser/signalr.js"></script>
    

클라이언트 .env 업데이트

  1. .env라는 이름의 client/start 폴더에 환경 변수 파일을 만듭니다.

  2. BACKEND_URL이라는 변수를 추가하고 단원 5에서 복사한 해당 값을 추가합니다.

    BACKEND_URL=https://YOUR-FUNTIONS-APP-NAME.azurewebsites.net
    

Azure Static Web Apps 리소스 만들기 및 클라이언트 배포

  1. Azure Portal을 열어 새 Azure Static Web Apps 리소스를 만듭니다.

  2. 다음 정보를 사용하여 리소스 만들기 기본 사항 탭을 완료합니다.

    속성
    Subscription 구독을 선택합니다.
    Resource group 리소스 그룹 stock-prototype을 사용합니다.
    정적 웹앱 이름 사용자의 이름을 client에 추가합니다. 예들 들어 client-jamie입니다.
    호스팅 계획 유형 무료를 선택합니다.
    배포 원본 GitHub를 선택합니다.
    조직 GitHub 계정 선택
    리포지토리 mslearn-advocates.azure-functions-and-signalr를 검색 및 선택합니다.
    지점 main 분기를 선택합니다.
    빌드 기본 설정 Vue.js를 선택합니다.
    앱 위치 /start/client를 입력합니다.
    API 위치 비워 둡니다.
    출력 위치 dist를 입력합니다.
  3. 워크플로 파일 미리 보기를 선택하여 배포 설정을 검토합니다. 빌드 및 배포 단계는 다음과 같습니다.

    - name: Build And Deploy
      id: builddeploy
      uses: Azure/static-web-apps-deploy@v1
      with:
        azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_123 }}
        repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
        action: "upload"
        ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
        # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
        app_location: "/solution/client" # App source code path
        api_location: "" # Api source code path - optional
        output_location: "dist" # Built app content directory - optional
        ###### End of Repository/Build Configurations ######
    
  4. 변경 내용을 저장하려면 닫기를 선택합니다.

  5. 검토 + 만들기를 선택한 다음 만들기를 선택하여 리소스를 만듭니다. 배포가 완료될 때까지 기다린 후 계속합니다.

  6. 리소스로 이동을 선택하여 새 Azure Static Web App 리소스를 엽니다.

  7. 개요 페이지에서 URL 값을 복사합니다. 이는 배포된 정적 웹앱의 기준 URL입니다.

리포지토리에 BACKEND_URL 변수 추가

워크플로에는 단위 5에서 배포된 Azure Functions 앱 기준 URL로 설정된 BACKEND_URL 환경 변수가 있어야 합니다.

  1. 샘플 리포지토리의 GitHub 포크용 브라우저에서 설정 -> 보안 -> 비밀 및 변수 -> Actions를 선택합니다.

  2. 변수를 선택한 다음 새 리포지토리 변수를 선택합니다.

  3. 다음 표를 사용하여 변수를 만듭니다.

    속성
    BACKEND_URL 배포된 Azure Functions 앱의 기준 URL입니다. URL은 https://<FUNCTIONS-RESOURCE-NAME>.azurewebsites.net 형식이어야 함
  4. 변수 추가를 선택하여 변수를 리포지토리에 저장합니다.

GitHub 배포 워크플로 편집

  1. Visual Studio Code 터미널에서 포크(원본)에서 새 워크플로 파일을 풀다운합니다.

    git pull origin main
    
  2. .github/workflows/azure-static-web-apps-*.yml 파일을 엽니다.

  3. 파일 상단의 name 값을 Client로 변경합니다.

  4. 빌드 및 배포 단계를 편집하여 BACKEND_URL 환경 변수에 대한 env 속성을 추가합니다.

    ```yaml
        name: Client - Azure Static Web Apps CI/CD
        
        on:
          push:
            branches:
              - main
          pull_request:
            types: [opened, synchronize, reopened, closed]
            branches:
              - main
        
        jobs:
          build_and_deploy_job:
            if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed')
            runs-on: ubuntu-latest
            name: Build and Deploy Job
            steps:
    
              - uses: actions/checkout@v3
                with:
                  submodules: true
                  lfs: false
    
              #Debug only - Did GitHub action variable get into workflow correctly?
              - name: Echo
                run: |
                  echo "BACKEND_URL: ${{ vars.BACKEND_URL }}"
    
              - name: Build And Deploy
                id: builddeploy
                uses: Azure/static-web-apps-deploy@v1
                with:
                  azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_123 }}
                  repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
                  action: "upload"
                  ###### Repository/Build Configurations - These values can be configured to match your app requirements. ######
                  # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig
                  app_location: "/solution/client" # App source code path
                  api_location: "" # Api source code path - optional
                  output_location: "dist" # Built app content directory - optional
                  ###### End of Repository/Build Configurations ######
                env: 
                  BACKEND_URL: ${{ vars.BACKEND_URL }}
    
          close_pull_request_job:
            if: github.event_name == 'pull_request' && github.event.action == 'closed'
            runs-on: ubuntu-latest
            name: Close Pull Request Job
            steps:
              - name: Close Pull Request
                id: closepullrequest
                uses: Azure/static-web-apps-deploy@v1
                with:
                  azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_123 }}
                  action: "close"
        ```
    
  5. 변경 내용을 저장하고 리포지토리에 푸시합니다.

    git add .
    git commit -m "Add BACKEND_URL environment variable"
    git push
    
  6. GitHub 포크 리포지토리에서 Actions 탭을 열어 배포를 봅니다.

함수 앱에서 CORS 업데이트

기본적으로 함수 앱은 CORS 요청을 허용하지 않습니다. 정적 웹앱의 요청을 허용하려면 함수 앱을 업데이트해야 합니다.

  1. Azure Portal에서 단원 5에서 만든 Azure Functions 앱으로 이동합니다.

  2. 왼쪽 메뉴에서 API -> CORS를 선택합니다.

  3. 액세스 제어 허용 자격 증명 사용을 선택합니다.

  4. Static Web Apps 리소스 URL에 대해 복사한 값을 추가합니다.

    속성
    허용된 원본 배포된 정적 웹앱의 기준 URL입니다.
  5. 저장을 선택하여 CORS 설정을 저장합니다.

클라이언트 배포 테스트

  1. 브라우저에서 배포된 정적 웹앱의 URL을 사용하여 클라이언트를 엽니다.
  2. 업데이트된 주식에 대한 SignalR 데이터가 언제 수신되는지 확인하려면 개발자 도구를 열어 콘솔을 살펴봅니다. 이는 HTTP 요청이 아니므로 네트워크 탭에 표시되지 않습니다.

축하합니다! SignalR을 사용하여 개선된 스톡 앱을 배포했습니다!