노트
이 기사는 최신 버전이 아닙니다. 현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.
경고
이 버전의 ASP.NET Core는 더 이상 지원되지 않습니다. 자세한 내용은 .NET 및 .NET Core 지원 정책을 참조하세요. 현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.
중요한
이 정보는 사전 출시 제품과 관련이 있으며, 상업적으로 출시되기 전에 상당히 수정될 수 있습니다. Microsoft는 여기 제공된 정보에 대해 명시적이거나 묵시적인 보증을 하지 않습니다.
현재 릴리스에 대해서는 본 기사의 .NET 9 버전을 참조하십시오.
Blazor 프로그레시브 웹 애플리케이션(PWA)은 현대 브라우저 API와 기능을 사용하여 데스크톱 앱처럼 작동하는 단일 페이지 애플리케이션(SPA)입니다.
Blazor WebAssembly는 표준 기반 클라이언트 측 웹 애플리케이션 플랫폼이므로 다음 기능에 필요한 PWA API를 포함하여 모든 브라우저 API를 사용할 수 있습니다.
- 네트워크 속도와 무관하게 오프라인으로 작동하며 즉시 로드됩니다.
- 자체 앱 창에서 실행되며, 단순히 브라우저 창뿐만은 아닙니다.
- 호스트의 운영 체제 시작 메뉴, 도킹 또는 홈 화면에서 시작됩니다.
- 사용자가 앱을 사용하지 않는 경우에도 백 엔드 서버에서 푸시 알림을 받습니다.
- 백그라운드에서 자동으로 업데이트 중입니다.
단어 progressive는 이러한 앱을 설명하는 데 사용됩니다. 그 이유는:
- 사용자는 먼저 다른 SPA와 마찬가지로 웹 브라우저 내에서 앱을 검색하고 사용할 수 있습니다.
- 나중에 사용자 은 운영 체제에서 이것을 설치하고 푸시 알림을 활성화합니다.
PWA 템플릿에서 프로젝트를 생성하세요.
새로운 Blazor WebAssembly 앱을 생성할 때, 진보적 웹 애플리케이션 체크박스를 선택하세요.
선택적으로, PWA는 ASP.NET Core HostedBlazor WebAssembly 프로젝트 템플릿에서 생성된 앱에 대해 구성할 수 있습니다. PWA 시나리오는 호스팅 모델과 독립적입니다.
기존 Blazor WebAssembly 앱을 PWA로 변환
이 섹션의 지침에 따라 기존 Blazor WebAssembly 앱을 PWA로 변환합니다.
앱의 프로젝트 파일에서:
다음 속성을 다음
ServiceWorkerAssetsManifest
속성에 추가합니다.PropertyGroup
... <ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest> </PropertyGroup>
다음 항목을 다음
ServiceWorker
항목에 추가합니다.ItemGroup
<ItemGroup> <ServiceWorker Include="wwwroot\service-worker.js" PublishedContent="wwwroot\service-worker.published.js" /> </ItemGroup>
정적 자산을 얻으려면 다음 접근 방식 중 하나를 사용하세요.
명령 셸에서
dotnet new
명령을 사용하여 별도의 새로운 PWA 프로젝트를 생성하세요.dotnet new blazorwasm -o MyBlazorPwa --pwa
이전 명령
-o|--output
에서 이 옵션은 이름이 지정된MyBlazorPwa
앱에 대한 새 폴더를 만듭니다.최신 릴리스를 위한 앱을 변환하지 않는 경우,
-f|--framework
옵션을 전달하세요. 다음 예제에서는 .NET 5용 앱을 만듭니다.dotnet new blazorwasm -o MyBlazorPwa --pwa -f net5.0
다음 URL에서 ASP.NET Core GitHub 저장소로 이동하면
main
브랜치 참조 소스 및 자산에 연결됩니다. 앱에 해당하는 브랜치 또는 태그 전환 드롭다운 목록에서 사용 중인 릴리스를 선택하세요.Blazor WebAssembly 프로젝트 템플릿
wwwroot
폴더 (dotnet/aspnetcore
GitHub 저장소main
브랜치)노트
문서 링크는 .NET 참조 소스를 가리키며, 일반적으로 저장소의 기본 브랜치를 로드합니다. 이는 .NET의 다음 릴리스를 위한 현재 개발 상태를 나타냅니다. 특정 릴리스를 위한 태그를 선택하려면 브랜치 또는 태그 전환 드롭다운 목록을 사용하세요. 추가 정보는 ASP.NET Core 소스 코드의 버전 태그 선택 방법 (dotnet/AspNetCore.Docs #26205)을 참조하세요.
당신이 만든 앱 또는
wwwroot
GitHub 저장소의 참조 자산에서dotnet/aspnetcore
폴더로부터 앱의wwwroot
폴더에 다음 파일을 복사하십시오.icon-192.png
icon-512.png
manifest.webmanifest
service-worker.js
service-worker.published.js
앱의 wwwroot/index.html
파일에서:
매니페스트 및 앱 아이콘에 대한
<link>
요소를 추가하십시오.<link href="manifest.webmanifest" rel="manifest" /> <link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" /> <link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
다음 URL에서 ASP.NET Core GitHub 저장소로 이동하세요. 이 URL은
v7.0.0
태그 참조 소스와 자산에 연결됩니다. .NET 8 이상을 사용하는 경우 이 문서의 맨 위에 있는 문서 버전 선택기를 변경하여 이 섹션에 대한 업데이트된 지침을 확인합니다. 앱에 해당하는 브랜치 또는 태그 전환 드롭다운 목록에서 사용 중인 릴리스를 선택하세요.Blazor WebAssembly 프로젝트 템플릿
wwwroot
폴더 (v7.0.0
태그)노트
문서 링크는 .NET 참조 소스를 가리키며, 일반적으로 저장소의 기본 브랜치를 로드합니다. 이는 .NET의 다음 릴리스를 위한 현재 개발 상태를 나타냅니다. 특정 릴리스를 위한 태그를 선택하려면 브랜치 또는 태그 전환 드롭다운 목록을 사용하세요. 추가 정보는 ASP.NET Core 소스 코드의 버전 태그 선택 방법 (dotnet/AspNetCore.Docs #26205)을 참조하세요.
당신이 만든 앱 또는
wwwroot
GitHub 저장소의 참조 자산에서dotnet/aspnetcore
폴더로부터 앱의wwwroot
폴더에 다음 파일을 복사하십시오.favicon.png
icon-192.png
icon-512.png
manifest.json
service-worker.js
service-worker.published.js
앱의 wwwroot/index.html
파일에서:
매니페스트 및 앱 아이콘에 대한
<link>
요소를 추가하십시오.<link href="manifest.json" rel="manifest" /> <link rel="apple-touch-icon" sizes="512x512" href="icon-512.png" /> <link rel="apple-touch-icon" sizes="192x192" href="icon-192.png" />
닫는
<script>
태그 안에 있는</body>
스크립트 태그 바로 뒤에 다음blazor.webassembly.js
태그를 추가합니다.... <script>navigator.serviceWorker.register('service-worker.js');</script> </body>
설치 및 앱 매니페스트
PWA 템플릿을 사용하여 만든 앱을 방문할 때 사용자는 OS의 시작 메뉴, 도킹 또는 홈 화면에 앱을 설치할 수 있습니다. 이 옵션의 표시 방식은 사용자의 브라우저에 따라 달라집니다. 데스크톱에서 Edge나 Chrome과 같은 Chromium 기반 브라우저를 사용할 때, URL 바에 추가 버튼이 나타납니다. 사용자가 추가 버튼을 선택하면 확인 대화상자가 나타납니다.
iOS에서는 방문자가 Safari의 공유 버튼과 홈 화면에 추가 옵션을 사용하여 PWA를 설치할 수 있습니다. 사용자는 Android용 Chrome에서 오른쪽 상단 모서리에 있는 메뉴 버튼을 선택한 다음, Home 화면에 추가를 선택해야 합니다.
설치가 완료되면 앱은 주소 표시줄이 없는 자체 창에서 나타납니다.
창의 제목, 색상 구성표, 아이콘, 또는 기타 세부 사항을 사용자 지정하려면 프로젝트의 manifest.json
디렉토리에 있는 wwwroot
파일을 참조하십시오. 이 파일의 스키마는 웹 표준에 의해 정의됩니다. 더 많은 정보를 보려면 MDN 웹 문서: 웹 앱 매니페스트를 참조하세요.
오프라인 지원
PWA 템플릿 옵션을 사용하여 만들어진 앱은 오프라인 상태에서도 실행할 수 있는 기능을 지원합니다. 사용자는 온라인 상태에서 먼저 앱을 방문해야 합니다. 브라우저는 자동으로 오프라인 작동에 필요한 모든 리소스를 다운로드하고 캐시합니다.
중요한
개발 지원은 변경 사항을 만들고 이를 시험하는 일반적인 개발 주기를 방해할 것입니다. 따라서 오프라인 지원은 출시된 앱에만 사용 가능합니다.
경고
오프라인 사용이 가능한 PWA를 배포하려면 몇 가지 중요한 경고와 주의사항이 있습니다. 이러한 시나리오는 오프라인 PWA에 내재되어 있으며 Blazor에 특정된 것이 아닙니다. 가정하기 전에 이러한 경고를 읽고 이해하십시오, 오프라인 기능이 있는 앱이 어떻게 작동하는지에 대해.
오프라인 지원이 어떻게 작동하는지 확인하려면:
앱을 발행하세요. 자세한 정보는 Host and deploy ASP.NET Core Blazor를 참조하세요.
앱을 HTTPS를 지원하는 서버에 배포하고, 보안 HTTPS 주소가 포함된 브라우저에서 앱에 접근하세요.
브라우저의 개발자 도구를 열고, 애플리케이션 탭에서 해당 호스트에 Service Worker가 등록되어 있는지 확인하십시오.
페이지를 새로고침하고 Network 탭을 검사하십시오. 모든 페이지 자산의 소스로 Service Worker 또는 메모리 캐시가 목록에 표시됩니다.
브라우저가 앱을 로드하기 위한 네트워크 액세스에 종속되지 않는지 확인하려면 다음 중 하나를 수행합니다.
- 웹 서버를 종료하고 페이지 새로고침을 포함한 앱이 정상적으로 작동하는 방식을 확인하세요. 마찬가지로 앱은 느린 네트워크 연결이 있을 때에도 정상적으로 작동합니다.
- 브라우저가 네트워크 탭에서 오프라인 모드를 시뮬레이션하도록 지시하세요.
서비스 워커를 사용한 오프라인 지원은 Blazor에 국한되지 않는 웹 표준입니다. 더 많은 서비스 워커에 대한 정보를 보려면 MDN 웹 문서: 서비스 워커 API를 참조하세요. 서비스 워커의 일반적인 사용 패턴에 대해 더 알아보려면 Google Web: The Service Worker Lifecycle를 참조하세요.
Blazor의 PWA 템플릿은 두 개의 서비스 워커 파일을 생성합니다.
-
wwwroot/service-worker.js
는 개발 중에 사용됩니다. -
wwwroot/service-worker.published.js
는 앱이 게시된 후에 사용됩니다.
두 개의 서비스 작업자 파일 간에 로직을 공유하려면, 다음 접근 방식을 고려해보세요.
- 공통 논리를 저장할 세 번째 JavaScript 파일을 추가합니다.
-
self.importScripts
를 사용하여 공통 로직을 두 개의 서비스 워커 파일에 로드하세요.
캐시 우선 가져오기 전략
내장된 service-worker.published.js
서비스 워커는 캐시 우선 전략을 사용하여 요청을 해결합니다. 즉, 서비스 작업자는 사용자가 네트워크에서 액세스할 수 있는지 또는 최신 콘텐츠를 서버에서 사용할 수 있는지 여부에 관계없이 캐시된 콘텐츠를 반환하는 것을 선호합니다.
캐시 우선 전략은 다음과 같은 이유로 가치가 있습니다:
신뢰성을 보장합니다. 네트워크 접근은 단순한 불리언 상태가 아닙니다. 사용자는 단순히 온라인 또는 오프라인 상태가 아닙니다.
- 사용자의 장치는 온라인 상태라고 가정할 수 있지만, 네트워크가 너무 느려서 기다리기에는 비실용적일 수 있습니다.
- 네트워크는 특정 URL에 대해 잘못된 결과를 반환할 수 있습니다. 특히 현재 특정 요청을 차단하거나 리디렉션하고 있는 캡티브 WIFI 포털이 있을 때 그렇습니다.
브라우저의
navigator.onLine
API가 신뢰할 수 없고 의존해서는 안 되는 이유입니다.정확성을 보장합니다. 오프라인 리소스의 캐시를 구축할 때, 서비스 워커는 콘텐츠 해싱을 사용하여 특정 시점에서 리소스의 완전하고 일관된 스냅샷을 가져왔다는 것을 보장합니다. 이 캐시는 원자 단위로 사용됩니다. 네트워크에 더 새로운 리소스를 요청하는 것은 의미가 없습니다. 필요한 버전은 이미 캐시에 저장되어 있기 때문입니다. 다른 옵션을 선택하면 불일치와 호환성 문제가 발생할 위험이 있습니다 (예를 들어, 함께 컴파일되지 않은 여러 버전의 .NET 어셈블리를 사용하려고 할 때).
서비스 워커의 새 버전을 배포할 때 임시 무결성 검사 실패를 해결하는 등의 이유로 브라우저가 HTTP 캐시에서 service-worker-assets.js
를 가져오는 것을 방지해야 하는 경우, wwwroot/index.html
을(를) 'none'으로 설정하여 updateViaCache
에서 서비스 워커 등록을 업데이트하세요.
<script>
navigator.serviceWorker.register('/service-worker.js', {updateViaCache: 'none'});
</script>
백그라운드 업데이트
정신적 모델로서, 모든 데이터를 항상 지역에 저장하는 PWA가 설치 가능한 모바일 앱처럼 동작한다고 생각할 수 있습니다. 네트워크 연결 여부와 관계없이 앱은 즉시 시작되지만, 설치된 앱의 로직은 최신 버전이 아닐 수도 있는 특정 시점의 스냅샷에서 가져옵니다.
Blazor PWA 템플릿은 사용자가 방문하고 인터넷 연결이 가능할 때마다 자동으로 백그라운드에서 업데이트를 시도하는 앱을 제공합니다. 이 방식은 다음과 같습니다:
- 컴파일 중에 프로젝트는 서비스 워커 자산 목록을 생성하며, 이 목록의 이름은
service-worker-assets.js
입니다. 매니페스트는 앱이 오프라인으로 작동하는 데 필요한 모든 정적 리소스를 나열하며, 여기에는 .NET 어셈블리, JavaScript 파일, CSS와 그들의 콘텐츠 해시가 포함됩니다. 서비스 워커가 캐시할 리소스를 알 수 있도록 리소스 목록이 로드됩니다. - 사용자가 앱을 방문할 때마다 브라우저는 백그라운드에서 다시 요청합니다
service-worker.js
service-worker-assets.js
. 파일들은 기존에 설치된 서비스 워커와 바이트 단위로 비교됩니다. 서버가 이 파일 중 하나의 변경된 콘텐츠를 반환하는 경우, 서비스 워커는 자신의 새 버전을 설치하려고 시도합니다. - 사용자가 새 버전을 설치할 때, 서비스 워커는 오프라인 리소스를 위한 새로운 별도의 캐시를 생성하고
service-worker-assets.js
에 나열된 리소스를 캐시에 채우기 시작합니다. 이 로직은onInstall
안의service-worker.published.js
함수에 구현되어 있습니다. - 모든 리소스가 오류 없이 로드되고 모든 콘텐츠 해시가 일치할 때 프로세스가 성공적으로 완료됩니다. 성공하면 새로운 서비스 워커는 활성화 대기 상태로 들어갑니다. 사용자가 앱을 종료하면(남아 있는 앱 탭이나 창이 없을 때), 새로운 서비스 워커가 활성화되어 이후 앱 방문 시 사용됩니다. 이전 서비스 워커와 해당 캐시는 삭제됩니다.
- 프로세스가 성공적으로 완료되지 않으면, 새로운 서비스 워커 인스턴스가 폐기됩니다. 사용자가 다음에 방문할 때 업데이트 과정이 다시 시도됩니다. 이때 요청을 완료할 수 있는 더 나은 네트워크 연결이 클라이언트에 있기를 바랍니다.
이 프로세스를 사용자 정의하려면 서비스 워커 로직을 편집하세요. 이전 행동 중 어느 것도 Blazor에 독특한 것이 아니라 PWA 템플릿 옵션이 제공하는 기본 경험에 불과합니다. 자세한 내용은 MDN 웹 문서: 서비스 워커 API를 참조하십시오.
요청이 해결되는 방법
캐시 우선 가져오기 전략 섹션에 설명된 바와 같이, 기본 서비스 워커는 캐시 우선 전략을 사용합니다. 이 전략은 사용 가능한 경우 캐시된 콘텐츠를 제공하려고 합니다. 특정 URL에 대해 캐시된 콘텐츠가 없으면, 예를 들어 백엔드 API에서 데이터를 요청할 때, 서비스 워커는 일반 네트워크 요청으로 대체하여 처리합니다. 서버에 접속할 수 있으면 네트워크 요청은 성공합니다.
onFetch
내에서 service-worker.published.js
함수 내부에 이 로직이 구현되어 있습니다.
앱의 Razor 구성 요소가 백엔드 API로부터 데이터를 요청하는 데 의존하고, 네트워크 불가용성으로 인해 요청 실패 시 사용자에게 친절한 경험을 제공하고자 한다면, 앱의 구성 요소 내에 적절한 논리를 구현하십시오. 예를 들어, try/catch
를 HttpClient 요청 주위에 사용하십시오.
서버 렌더링 페이지 지원
사용자가 앱에서 /counter
또는 다른 딥 링크와 같은 URL에 처음으로 이동할 때 발생하는 일을 고려하십시오. 이러한 경우 /counter
로 캐시된 콘텐츠를 반환하지 않고, 대신 /index.html
로 캐시된 콘텐츠를 로드하여 Blazor WebAssembly 앱을 시작해야 합니다. 초기 요청은 탐색 요청으로 알려져 있으며, 이와 대조적으로:
-
subresource
이미지, 스타일 시트 또는 다른 파일 요청. -
fetch/XHR
API 데이터 요청.
기본 서비스 작업자는 탐색 요청에 대한 특수 사례 논리를 포함합니다. 서비스 워커는 요청된 URL에 관계없이 /index.html
에 대한 캐시한 콘텐츠를 반환하여 요청을 해결합니다. 이 로직은 onFetch
안의 service-worker.published.js
함수에 구현되어 있습니다.
앱에 서버에서 렌더링된 HTML을 반환해야 하고 캐시에서 /index.html
을 제공하지 않아야 하는 특정 URL이 있는 경우, 서비스 워커의 로직을 수정해야 합니다. 서버에 대한 모든 URL이 /Identity/
를 포함하고 있는 경우 일반적인 온라인 전용 요청으로 처리되어야 한다면, service-worker.published.js
onFetch
로직을 수정하십시오. 다음 코드를 찾으십시오.
const shouldServeIndexHtml = event.request.mode === 'navigate';
코드를 다음으로 변경하십시오:
const shouldServeIndexHtml = event.request.mode === 'navigate'
&& !event.request.url.includes('/Identity/');
이 작업을 수행하지 않으면 네트워크 연결에 관계없이 서비스 작업자는 이러한 URL에 대한 요청을 가로채고 이를 사용하여 /index.html
해결합니다.
외부 인증 제공자 확인에 추가적인 엔드포인트를 추가하세요. 다음 예시에서 Google 인증을 위한 /signin-google
이 확인에 추가됩니다.
const shouldServeIndexHtml = event.request.mode === 'navigate'
&& !event.request.url.includes('/Identity/')
&& !event.request.url.includes('/signin-google');
Development
환경에 대해서는 네트워크에서 항상 콘텐츠가 가져와지므로 별도의 조치가 필요하지 않습니다.
자산 캐시 제어
프로젝트에서 ServiceWorkerAssetsManifest
MSBuild 속성을 정의하면, Blazor의 빌드 도구가 지정된 이름으로 서비스 워커 자산 매니페스트를 생성합니다. 기본 PWA 템플릿은 다음 속성이 포함된 프로젝트 파일을 생성합니다.
<ServiceWorkerAssetsManifest>service-worker-assets.js</ServiceWorkerAssetsManifest>
파일은 wwwroot
출력 디렉터리에 저장되므로, 브라우저는 /service-worker-assets.js
요청을 통해 이 파일을 가져올 수 있습니다. 이 파일의 내용을 보려면 텍스트 편집기에서 /bin/Debug/{TARGET FRAMEWORK}/wwwroot/service-worker-assets.js
을(를) 열어보세요. 하지만 파일을 편집하지 마세요. 각 빌드 때마다 다시 생성됩니다.
명세서는 다음과 같이 나열됩니다:
- .NET 어셈블리 및 오프라인 기능에 필요한 .NET WebAssembly 런타임 파일과 같은 Any Blazor-관리 리소스.
- 외부 프로젝트 및 NuGet 패키지에서 제공하는 정적 웹 자산을 포함하여 이미지, 스타일시트 및 JavaScript 파일과 같은 앱의
wwwroot
디렉터리에 게시하기 위한 모든 리소스입니다.
서비스 워커가 가져와서 캐시할 리소스를 제어하려면 onInstall
의 service-worker.published.js
에서 로직을 편집하십시오. 서비스 작업자는 일반적인 웹 파일 이름 확장자인 .html
, .css
, .js
, .wasm
에 일치하는 파일과 Blazor WebAssembly에 특정한 파일 형식 및 .pdb
파일(모든 버전), .dll
파일(.NET 7 이하의 ASP.NET Core)을 가져와서 캐시합니다.
앱의 wwwroot
디렉터리에 없는 추가 리소스를 포함하려면 다음 예제와 같이 추가 MSBuild ItemGroup
항목을 정의합니다.
<ItemGroup>
<ServiceWorkerAssetsManifestItem Include="MyDirectory\AnotherFile.json"
RelativePath="MyDirectory\AnotherFile.json" AssetUrl="files/AnotherFile.json" />
</ItemGroup>
AssetUrl
메타데이터는 브라우저가 리소스를 가져와서 캐시할 때 사용해야 하는 기본 상대 URL을 지정합니다. 디스크의 원래 원본 파일 이름과는 독립적일 수 있습니다.
중요한
ServiceWorkerAssetsManifestItem
를 추가하더라도 파일이 앱의 wwwroot
디렉터리에 게시되지 않습니다. 게시 출력은 별도로 제어되어야 합니다.
ServiceWorkerAssetsManifestItem
는 서비스 워커 자산 매니페스트에 추가 항목이 나타나게 할 뿐입니다.
푸시 알림
다른 PWA와 마찬가지로, Blazor WebAssembly PWA는 백엔드 서버로부터 푸시 알림을 받을 수 있습니다. 서버는 사용자가 앱을 적극적으로 사용하지 않을 때라도 언제든지 푸시 알림을 보낼 수 있습니다. 예를 들어 다른 사용자가 관련 작업을 수행할 때 푸시 알림을 보낼 수 있습니다.
오프라인 PWA에 대한 주의사항
모든 앱이 오프라인 사용을 지원하려고 시도하는 것은 아닙니다. 오프라인 지원은 상당한 복잡성을 더하지만 필요한 사용 사례와 항상 관련이 있는 것은 아닙니다.
오프라인 지원은 보통 다음의 경우에만 관련이 있습니다.
- 주 데이터 저장소가 브라우저에 로컬로 설정되어 있는 경우. 예를 들어, 이 접근 방식은 데이터를 또는
localStorage
에 저장하는 IoT 장치의 UI를 갖춘 앱에서 관련이 있습니다. - 앱이 각 사용자와 관련된 백엔드 API 데이터를 가져오고 캐시하는 작업을 많이 수행하여 사용자가 오프라인에서 데이터를 탐색할 수 있도록 하는 경우. 앱이 편집을 지원해야 한다면, 변경 사항을 추적하고 백엔드와 데이터를 동기화하기 위한 시스템이 구축되어야 합니다.
- 네트워크 상태와 상관없이 앱이 즉시 로드되도록 보장하는 것이 목표라면. 백엔드 API 요청에 대한 적절한 사용자 경험을 구현하여 요청 진행 상황을 표시하고 네트워크 불가로 인해 요청이 실패할 때 타당하게 대응하도록 합니다.
또한 오프라인 기능을 갖춘 PWA는 추가적인 여러 가지 문제를 처리해야 합니다. 개발자는 다음 섹션의 주의 사항에 주의해야 합니다.
게시된 후에만 오프라인 지원 가능
개발 중에는 각 변경 사항이 백그라운드 업데이트 과정을 거치지 않고 즉시 브라우저에 반영되기를 원합니다. 따라서 BlazorPWA 템플릿을 사용하면 게시된 경우에만 오프라인 지원을 사용할 수 있습니다.
오프라인 지원 앱을 빌드하는 경우 환경에서 앱을 Development
테스트하는 것만으로는 충분하지 않습니다. 게시된 상태에서 앱을 테스트하여 다양한 네트워크 조건에 응답하는 방법을 이해해야 합니다.
사용자가 앱을 벗어날 때 업데이트 완료
사용자가 모든 탭에서 앱을 벗어나기 전까지 업데이트가 완료되지 않습니다. 백그라운드 업데이트 섹션에서 설명한 바와 같이, 앱에 업데이트를 배포한 후, 브라우저는 업데이트된 서비스 워커 파일을 가져와 업데이트 프로세스를 시작합니다.
많은 개발자를 놀라게 하는 것은 이 업데이트가 완료되더라도, 사용자가 모든 탭에서 벗어날 때까지 업데이트가 적용되지 않는다는 점입니다. 앱을 표시하는 유일한 탭인 경우에도 앱을 표시하는 탭을 새로 고치는 것만으로는 충분하지 않습니다. 앱이 완전히 닫힐 때까지 새 서비스 워커는 활성화 대기 상태로 남아 있습니다. 이것은 Blazor에 특정한 것이 아니라 표준 웹 플랫폼 동작입니다.
일반적으로 서비스 작업자 또는 오프라인 캐시된 리소스에 대한 업데이트를 테스트하려는 개발자에게 문제가 발생합니다. 브라우저의 개발자 도구를 체크 인하면 다음과 같이 표시할 수 있습니다.
"귀하의 앱을 표시하는 탭이나 창으로 구성된 '클라이언트' 목록이 비어 있지 않는 한, 작업자는 계속 기다립니다." 서비스 직원들이 이렇게 하는 이유는 일관성을 보장하기 위해서입니다. 일관성은 모든 리소스가 동일한 원자적 캐시에서 가져온다는 것을 의미합니다.
변경사항을 테스트할 때, 앞의 스크린샷에 표시된 "skipWaiting" 링크를 선택하고 페이지를 새로 고치는 것이 편리할 수 있습니다. 모든 사용자에 대해 이를 자동화하려면 서비스 워커를 코딩하여 "대기" 단계 건너뛰기 및 업데이트 시 즉시 활성화하도록 하세요. 대기 단계를 건너뛴다면, 자원이 항상 동일한 캐시 인스턴스에서 일관되게 가져온다는 보장을 포기하는 셈입니다.
사용자는 앱의 모든 과거 버전을 실행할 수 있습니다.
웹 개발자는 기존 웹 배포 모델 내에서 정상이므로 사용자가 최신 배포된 버전의 웹앱만 실행한다고 습관적으로 예상합니다. 그러나 오프라인 우선 PWA는 사용자가 반드시 최신 버전을 실행하지 않는 네이티브 모바일 앱과 더 비슷합니다.
백그라운드 업데이트 섹션에서 설명한 대로, 앱에 업데이트를 배포한 후 기존 사용자는 업데이트가 백그라운드에서 이루어지고 사용자가 이동할 때까지 활성화되지 않기 때문에 적어도 한 번 더 이전 버전을 계속 사용합니다. 게다가 사용되고 있는 이전 버전이 꼭 배포한 이전 버전은 아닙니다. 이전 버전은 사용자가 마지막으로 업데이트를 완료한 시기에 따라 어느 이전 버전일 수 있습니다.
앱의 프론트엔드와 백엔드 부분이 API 요청을 위한 스키마에 대해 동의가 필요한 경우, 이 문제가 발생할 수 있습니다. 모든 사용자가 업그레이드했음을 확신할 수 있을 때까지 하위 호환성을 없는 API 스키마 변경을 배포해서는 안 됩니다. 대신 사용자가 호환되지 않는 이전 버전의 앱을 사용하는 것을 차단하십시오. 이 시나리오 요구 사항은 네이티브 모바일 앱과 동일합니다. 서버 API에 중대한 변화를 배포하면 아직 업데이트하지 않은 사용자들의 클라이언트 앱이 작동하지 않게 됩니다.
가능하다면, 백엔드 API에 파괴적인 변경 사항을 배포하지 마세요. 이렇게 해야 하는 경우 ServiceWorkerRegistration과 같은 표준 Service Worker API 를 사용하여 앱이 up-to있는지 여부를 확인하고 그렇지 않은 경우 사용을 방지하는 것이 좋습니다.
서버에서 렌더링된 페이지에 대한 간섭
서버 렌더링 페이지 지원 섹션에서 설명한 바와 같이, 모든 탐색 요청에 대해 /index.html
콘텐츠를 반환하는 서비스 워커의 동작을 우회하려면, 서비스 워커의 로직을 편집하십시오.
모든 서비스 워커 자산 매니페스트 내용은 캐시됩니다.
자산 캐싱 제어 섹션에 설명된 대로, service-worker-assets.js
파일은 빌드 중에 생성되어 서비스 워커가 가져와 캐시해야 하는 모든 자산을 나열합니다.
외부 패키지나 프로젝트에서 제공되는 콘텐츠를 포함하여 wwwroot
에 전송된 모든 것을 이 목록에 포함시키기 때문에, 너무 많은 콘텐츠를 넣지 않도록 주의해야 합니다.
wwwroot
디렉토리에 수백만 개의 이미지가 포함되어 있는 경우, 서비스 워커는 모두 가져와 캐시하려고 시도하며, 이는 과도한 대역폭을 소비하고 대부분 성공적으로 완료되지 않을 것입니다.
매니페스트의 내용 중 어느 부분을 가져와 캐시할지를 제어하는 임의의 로직을 구현하려면 onInstall
의 service-worker.published.js
함수를 편집하십시오.
인증과의 상호작용
PWA 템플릿은 인증과 함께 사용할 수 있습니다. 네트워크가 처음 연결된 상태에서는 오프라인 기능이 있는 PWA도 인증을 지원할 수 있습니다.
사용자가 네트워크 연결이 없으면 인증하거나 액세스 토큰을 받을 수 없습니다. 네트워크에 연결되지 않은 상태에서 로그인 페이지에 접속을 시도하면 "네트워크 오류" 메시지가 나타납니다. 사용자를 인증하거나 액세스 토큰을 얻으려 하지 않고, 사용자가 오프라인 상태에서 유용한 작업을 수행할 수 있도록 하는 UI 흐름을 설계해야 합니다. 또한 네트워크가 사용할 수 없을 때 앱이 부드럽게 작동하도록 설계할 수 있습니다. 이러한 시나리오를 처리하도록 앱을 설계할 수 없는 경우 오프라인 지원을 사용하지 않으려는 것일 수 있습니다.
온라인 및 오프라인 사용을 위해 설계된 앱이 다시 온라인 상태가 될 때:
- 앱이 새 액세스 토큰을 제공해야 할 수 있습니다.
- 앱은 다른 사용자가 서비스에 로그인했는지 감지해야 하며, 이렇게 함으로써 사용자가 오프라인 상태에서 이루어진 작업을 그 사용자의 계정에 적용할 수 있습니다.
인증과 상호 작용하는 오프라인 PWA 앱을 만들려면 다음을 수행합니다.
- AccountClaimsPrincipalFactory<TAccount>를 마지막 로그인한 사용자를 저장하고 앱이 오프라인일 때 저장된 사용자를 사용하는 팩토리로 교체하십시오.
- 앱이 오프라인일 때 작업을 대기열에 추가하고, 앱이 온라인으로 돌아오면 해당 작업을 적용하십시오.
- 로그아웃하는 동안 저장된 사용자를 지웁다.
CarChecker
샘플 앱은 앞서 언급한 접근 방식을 보여줍니다. 앱의 다음 부분을 확인하세요:
-
OfflineAccountClaimsPrincipalFactory
(Client/Data/OfflineAccountClaimsPrincipalFactory.cs
) -
LocalVehiclesStore
(Client/Data/LocalVehiclesStore.cs
) -
LoginStatus
구성 요소(Client/Shared/LoginStatus.razor
)
추가 자료
ASP.NET Core