Azure Static Web Apps에 하이브리드 Next.js 웹 사이트 배포(미리 보기)

이 자습서에서는 React Server 구성 요소, SSR(서버 쪽 렌더링) 및 API 경로와 같은 Next.js 기능에 대한 지원을 사용하여 Next.js 웹 사이트를 Azure Static Web Apps에 배포 하는 방법을 알아봅니다.

참고 항목

Next.js 하이브리드 지원은 미리 보기로 제공됩니다.

필수 조건

미리 보기에서 지원되지 않는 기능

Static Web Apps의 다음 기능은 하이브리드 렌더링을 사용하는 Next.js 지원되지 않습니다.

  • Azure Functions, Azure 앱 Service, Azure Container Apps 또는 Azure API Management를 사용하는 연결된 API입니다.
  • SWA CLI 로컬 에뮬레이션 및 배포.
  • 파일에 대한 staticwebapp.config.json 부분 지원입니다.
    • 탐색 대체는 지원되지 않습니다.
    • Next.js 애플리케이션 내의 경로에 대한 경로 다시 쓰기를 구성 next.config.js해야 합니다.
    • 파일 next.config.js내의 구성이 staticwebapp.config.json .
    • 전체 기능 호환성을 위해 next.config.js Next.js 사이트에 대한 구성을 처리해야 합니다.
  • skip_app_buildskip_api_build 배포 이미지 내에서 Azure/static-web-apps-deploy@v1 사용할 수 없습니다.
  • ISR(증분 정적 다시 생성)은 이미지 캐싱을 지원하지 않습니다.

참고 항목

하이브리드 Next.js 애플리케이션의 최대 앱 크기는 250MB입니다. 최적화된 앱 크기에 Next.js의 독립 실행형 기능을 사용합니다. 이것이 충분하지 않은 경우 앱 크기 요구 사항이 250MB를 초과하는 경우 Next.js 내보낸 정적 HTML을 사용하는 것이 좋습니다.

리포지토리 만들기

이 문서에서는 GitHub 템플릿 리포지토리를 사용하여 쉽게 시작할 수 있습니다. 이 템플릿에는 Azure Static Web Apps에 배포할 스타터 앱이 있습니다.

  1. 다음 위치로 이동하여 새 리포지토리를 만듭니다.

    https://github.com/staticwebdev/nextjs-hybrid-starter/generate

  2. 리포지토리 이름을 my-first-static-web-app으로 지정합니다.

  3. 템플릿에서 리포지토리 만들기를 선택합니다.

    템플릿 단추에서 리포지토리 만들기 스크린샷

정적 웹앱 만들기

이제 리포지토리가 생성되었으므로 Azure Portal에서 정적 웹앱을 만들 수 있습니다.

  1. Azure Portal로 이동합니다.
  2. 리소스 만들기를 선택합니다.
  3. Static Web Apps를 검색합니다.
  4. Static Web Apps를 선택합니다.
  5. 만들기를 실행합니다.

기본 사항 섹션에서 새 앱을 구성하고 GitHub 리포지토리에 연결하여 시작합니다.

Azure Portal의 기본 섹션 스크린샷

설정
Subscription Azure 구독을 선택합니다.
리소스 그룹 새로 만들기 링크를 선택하고 텍스트 상자에 static-web-apps-test를 입력합니다.
이름 텍스트 상자에 my-first-static-web-app을 입력합니다.
플랜 유형 무료를 선택합니다.
Azure Functions 및 준비 정보 가장 가까운 지역을 선택합니다.
원본 GitHub를 선택합니다.

GitHub로 로그인을 선택하고 GitHub로 인증합니다.

GitHub로 로그인한 후 리포지토리 정보를 입력합니다.

설정
조직 조직을 선택합니다.
리포지토리 my-first-web-static-app을 선택합니다.
Branch 기본을 선택합니다.

Azure Portal의 리포지토리 세부 정보 스크린샷

참고 항목

리포지토리가 표시되지 않는 경우:

  • GitHub에서 Azure Static Web Apps에 권한을 부여해야 할 수 있습니다. GitHub 리포지토리로 이동하여 설정 > 애플리케이션 > 권한 부여된 OAuth 앱으로 이동하고 Azure Static Web Apps를 선택한 다음, 권한 부여를 선택합니다.
  • Azure DevOps 조직에서 Azure Static Web Apps에 권한을 부여해야 할 수 있습니다. 사용 권한을 부여하려면 조직의 소유자여야 합니다. OAuth를 통해 타사 애플리케이션 액세스를 요청합니다. 자세한 내용은 OAuth 2.0을 사용하여 REST API에 대한 액세스 권한 부여를 참조하세요.

빌드 세부 정보 섹션에서 선호하는 프런트 엔드 프레임워크와 관련된 구성 세부 정보를 추가합니다.

  1. 빌드 사전 설정 드롭다운에서 Next.js 선택합니다.

  2. 앱 위치 상자에서 기본값을 유지합니다.

  3. Api 위치 상자를 비워 둡니다.

  4. 앱 아티팩트 위치 상자를 비워 둡니다.

검토 + 만들기를 선택합니다.

만들기 단추의 스크린샷.

웹 사이트 보기

정적 앱을 배포하는 데는 두 가지 측면이 있습니다. 먼저 앱을 구성하는 기본 Azure 리소스를 만듭니다. 두 번째는 애플리케이션을 빌드하고 게시하는 워크플로입니다.

새 정적 사이트로 이동하려면 먼저 배포 빌드가 실행을 완료해야 합니다.

Static Web Apps 개요 창에는 웹앱과 상호 작용하는 데 도움이 되는 일련의 링크가 표시됩니다.

Azure Static Web Apps 개요 창의 스크린샷.

GitHub Actions 실행 상태를 확인하려면 여기를 선택하세요.라는 배너를 선택하면 리포지토리에 대해 실행 중인 GitHub Actions로 이동됩니다. 배포 작업이 완료되었는지 확인되면 생성된 URL을 통해 웹 사이트로 이동할 수 있습니다.

GitHub Actions 워크플로가 완료되면 URL 링크를 선택하여 새 탭에서 웹 사이트를 열 수 있습니다.

Next.js 프로젝트를 로컬로 설정하여 변경

  1. 컴퓨터에 새 리포지토리를 복제합니다. <YOUR_GITHUB_ACCOUNT_NAME>을 계정 이름으로 바꾸어야 합니다.

    git clone http://github.com/<YOUR_GITHUB_ACCOUNT_NAME>/my-first-static-web-app
    
  2. Visual Studio Code 또는 기본 코드 편집기에서 프로젝트를 엽니다.

서버 구성 요소를 사용하여 서버 렌더링 데이터 추가

앱 라우터를 사용하여 Next.js 프로젝트에 서버 렌더링 데이터를 추가하려면 Next.js 구성 요소를 편집하여 구성 요소에서 데이터를 렌더링하는 서버 쪽 작업을 추가합니다. 기본적으로 Next.js 구성 요소는 서버 렌더링할 수 있는 서버 구성 요소입니다.

  1. app/page.tsx 파일을 열고 계산된 서버 쪽 변수의 값을 설정하는 작업을 추가합니다. 예를 들어 데이터 가져오기 또는 다른 서버 작업이 있습니다.

    export default function Home() {
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            ...
        );
    }
    
  2. 경로가 동적으로 렌더링되도록 구성 요소 내에서 next/cacheHome 가져오 unstable_noStore 고 호출합니다.

    import { unstable_noStore as noStore } from 'next/cache';
    
    export default function Home() {
        noStore();
    
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            ...
        );
    }
    

    참고 항목

    이 예제에서는 이 구성 요소의 동적 렌더링을 강제로 서버의 현재 시간의 서버 렌더링을 보여 줍니다. Next.js 앱 라우터 모델은 개별 데이터 요청을 캐싱하여 Next.js 앱의 성능을 최적화하는 것이 좋습니다. Next.js 데이터 페치 및 캐싱에 대해 자세히 읽어보세요.

  3. Home app/pages.tsx구성 요소를 업데이트하여 서버 쪽 데이터를 렌더링합니다.

    import { unstable_noStore as noStore } from 'next/cache';
    
    export default function Home() {
        noStore();
    
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            <main className="flex min-h-screen flex-col items-center justify-between p-24">
                <div>
                    This is a Next.js application hosted on Azure Static Web Apps with 
                    hybrid rendering. The time on the server is <strong>{timeOnServer}</strong>.
                </div>
            </main>
        );
    }
    

API 경로 추가

Next.js 서버 구성 요소 외에도 Next.js 애플리케이션에 대한 API 경로를 만드는 데 사용할 수 있는 경로 처리기를 제공합니다. 이러한 API는 클라이언트 구성 요소에서 가져올 수 있습니다.

먼저 API 경로를 추가합니다.

  1. 에서 새 파일을 만듭니다 app/api/currentTime/route.tsx. 이 파일은 새 API 엔드포인트에 대한 경로 처리기를 보유합니다.

  2. API에서 데이터를 반환하는 처리기 함수를 추가합니다.

    import { NextResponse } from 'next/server';
    
    export const dynamic = 'force-dynamic';
    
    export async function GET() { 
        const currentTime = new Date().toLocaleTimeString('en-US');
    
        return NextResponse.json({ 
            message: `Hello from the API! The current time is ${currentTime}.`
        });
    }
    
  3. 에서 새 파일을 만듭니다 app/components/CurrentTimeFromAPI.tsx. 이 구성 요소는 브라우저에서 API를 가져오는 클라이언트 구성 요소에 대한 컨테이너를 만듭니다.

  4. 이 파일에서 API를 가져오는 클라이언트 구성 요소를 추가합니다.

    'use client';
    
    import { useEffect, useState } from 'react';
    
    export function CurrentTimeFromAPI(){
        const [apiResponse, setApiResponse] = useState('');
        const [loading, setLoading] = useState(true);
    
        useEffect(() => {
            fetch('/api/currentTime')
                .then((res) => res.json())
                .then((data) => {
                setApiResponse(data.message);
                setLoading(false);
                });
            }, 
        []);
    
        return (
            <div className='pt-4'>
                The message from the API is: <strong>{apiResponse}</strong>
            </div>
        )
    }
    

이 클라이언트 구성 요소는 부하가 완료된 후 구성 요소를 렌더링하기 위해 React 후크를 사용하여 API useEffect 를 가져옵니다. 지시문은 'use client' 이 요소를 클라이언트 구성 요소로 식별합니다. 자세한 내용은 클라이언트 구성 요소를 참조 하세요.

  1. app/page.tsx를 편집하여 클라이언트 구성 요소를 가져오고 렌더링 CurrentTimeFromAPI 합니다.

    import { unstable_noStore as noStore } from 'next/cache';
    import { CurrentTimeFromAPI } from './components/CurrentTimeFromAPI';
    
    export default function Home() {
        noStore();
    
        const timeOnServer = new Date().toLocaleTimeString('en-US');
        return(
            <main className="flex min-h-screen flex-col items-center justify-between p-24">
                <div>
                    This is a Next.js application hosted on Azure Static Web Apps with 
                    hybrid rendering. The time on the server is <strong>{timeOnServer}</strong>.
                </div>
                <CurrentTimeFromAPI />
            </main>
        );
    }
    
  2. API 경로의 결과가 페이지에 표시됩니다.

API 경로의 출력 표시를 보여 주는 스크린샷

Next.js 런타임 버전 구성

특정 Next.js 버전에는 특정 Node.js 버전이 필요합니다. 특정 노드 버전을 구성하려면 파일의 package.json '엔진' 속성을 설정하여 버전을 지정할 수 있습니다.

{
  ...
  "engines": {
    "node": "18.17.1"
  }
}

Next.js 환경 변수 설정

Next.js 빌드 시 및 요청 시 환경 변수를 사용하여 서버 쪽 렌더링을 통해 정적 페이지 생성 및 동적 페이지 생성을 모두 지원합니다. 따라서 빌드 및 배포 작업 및 Azure Static Web Apps 리소스의 환경 변수 모두에서 환경 변수를 설정합니다.

...
      - 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 }}
          repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments)
          action: "upload"
          app_location: "/" 
          api_location: ""
          output_location: "" 
        env:
          DB_HOST: ${{ secrets.DB_HOST }}
          DB_USER: ${{ secrets.DB_USER }}
          DB_DATABASE: ${{ secrets.DB_DATABASE }}
          DB_PASSWORD: ${{ secrets.DB_PASSWORD }}
          DB_PORT: ${{ secrets.DB_PORT }}
...

독립 실행형 기능 사용

애플리케이션 크기가 250Mb를 초과하면 Next.js 출력 파일 추적 기능을 통해 앱 크기를 최적화하고 성능을 향상시킬 수 있습니다.

출력 파일 추적은 .next/standalone이라는 폴더에 기본 제공되는 필요한 패키지 종속성을 사용하여 압축된 전체 애플리케이션 버전을 만듭니다. 이 폴더는 추가 node_modules 종속성 없이 자체적으로 배포하기 위한 것입니다.

standalone 기능을 사용하도록 설정하려면 next.config.js에 다음 속성을 더 추가합니다.

module.exports ={
    output:"standalone",
}

또한 정적 파일을 독립 실행형 출력에 복사하기 위해 파일에서 명령을 package.json 구성 build 해야 합니다.

{
  ...
  "scripts": {
    ...
    "build": "next build && cp -r .next/static .next/standalone/.next/ && cp -r public .next/standalone/"
    ...
  }
  ...
}

Azure Static Web Apps에 배포할 Next.js 라우팅 및 미들웨어 구성

Next.js 프로젝트는 리디렉션, 다시 쓰기 및 미들웨어를 사용하여 경로를 사용자 지정 처리하도록 구성할 수 있습니다. 이러한 처리기는 일반적으로 인증, 개인 설정, 라우팅 및 국제화에 사용됩니다. 사용자 지정 처리는 Next.js 사이트의 기본 라우팅에 영향을 줍니다. 구성은 Static Web Apps의 호스팅과 호환되어야 합니다.

Static Web Apps는 빌드 시 사이트에 페이지를 추가하여 Next.js 사이트가 성공적으로 배포되었는지 확인합니다. 페이지의 이름이 지정 public/.swa/health.html되고 Static Web Apps는 성공적인 응답을 탐색하고 확인하여 /.swa/health.html 사이트의 성공적인 시작 및 배포를 확인합니다. 리디렉션 및 다시 쓰기를 포함하는 미들웨어 및 사용자 지정 라우팅은 경로 액세스 /.swa/health.html 에 영향을 줄 수 있으므로 Static Web Apps의 배포 유효성 검사를 방지할 수 있습니다. Static Web Apps에 성공적으로 배포할 미들웨어 및 라우팅을 구성하려면 다음 단계를 수행합니다.

  1. 미들웨어 구성의 middleware.ts (또는.js) 파일에서 시작하는 .swa 경로를 제외합니다.

    export const config = {
      matcher: [
        /*
         * Match all request paths except for the ones starting with:
         * - .swa (Azure Static Web Apps)
         */
        '/((?!.swa).*)',
      ],
    }
    
  2. 다음으로 시작하는 경로를 제외하도록 리디렉션 next.config.js 구성 .swa

    module.exports = {
        async redirects() {
            return [
              {
                source: '/((?!.swa).*)<YOUR MATCHING RULE>',
                destination: '<YOUR REDIRECT RULE>', 
                permanent: false,
              },
            ]
        },
    };
    
  3. 로 시작하는 경로를 제외하도록 재작성 next.config.js 구성 .swa

    module.exports = {
        async rewrites() {
            return {
                beforeFiles: [
                    {
                        source: '/((?!.swa).*)<YOUR MATCHING RULE>',
                        destination: '<YOUR REWRITE RULE>', 
                    }
                ]
            }
        },
    };
    

이러한 코드 조각은 사용자 지정 라우팅 또는 미들웨어에서 처리되는 것으로 시작하는 .swa 경로를 제외합니다. 이러한 규칙은 배포 유효성 검사 중에 경로가 예상대로 확인되도록 합니다.

Next.js 로깅 사용

Next.js 서버 API 문제 해결 모범 사례에 따라 API에 로깅을 추가하여 이러한 오류를 catch합니다. Azure에서 로깅은 Application Insights를 사용합니다. 이 SDK를 미리 로드하려면 사용자 지정 시작 스크립트를 만들어야 합니다. 자세히 알아보려면 다음을 수행합니다.

리소스 정리

이 애플리케이션을 계속 사용하지 않을 경우 다음 단계를 통해 Azure Static Web App 인스턴스를 삭제할 수 있습니다.

  1. Azure Portal을 엽니다.
  2. 위쪽 검색 창에서 my-first-web-static-app을 검색합니다.
  3. 앱 이름을 선택합니다.
  4. 삭제를 선택합니다.
  5. 를 선택하여 삭제 작업을 확인합니다(이 작업은 완료하는 데 몇 분 정도 걸릴 수 있음).

다음 단계