Blazor 로 구현하는 경우 Server 부하를 줄이기 위해 WebAssembly 형태로 구현한 경우 고려할 사항이 있습니다.
사용자 PC 에 다운로드 되는 시간이 소요되기 때문에 처음 접속 시 상대적으로 기다려야 하는 시간이 늘어나게 됩니다.
이때, 용량이 크거나 네트워크 상태로 인해 접속 시간이 길어지면 사용자는 기다리지 않고 이탈하게 됩니다.
그래서, 다운로드가 완료되고 화면에 표시되기 전까지 로딩중임을 표현하게 됩니다.
.net 6 으로 구현할 당시에는 Visual Studio 기본 템플릿에서 디자인 추가 및 코드 수정이 필요했었습니다.
그리고 .net 7 에서는 Visual Studio 기본 템플릿에 진행율을 표시하는 디자인 및 css 코드가 추가되었습니다.
그런데, 이번에 .net 8 로 넘어가면서 Blazor Web App Template 으로 마이그레이션 하고
InteractiveWebAssemblyRenderMode 로 수정하게 되었습니다.
하지만 이상하게도 Visual Studio 기본 템플릿으로 생성된 코드에는 진행율을 표시하는 코드가 존재하지 않습니다.
(차후에 추가가 될지도 모르지만 2023-12-06 일 기준입니다.)
그래서 버전 별로 구현 방법 및 차이점을 비교해서 살펴보겠습니다.
프로젝트 생성
Visual Studio 2022 에서 기본 템플릿으로 생성해서 간단하게 살펴보겠습니다.
다음과 같이 프로젝트를 생성해 주세요.
.Net 6
Blazor WebAssembly App
.Net 7
Blazor WebAssembly App
.Net 8
Blazor Web App
솔루션 폴더로 다음과 같이 구분하겠습니다.
.Net 6 Blazor WebAssembly App
Client 프로젝트의 wwwroot 폴더에 있는 index.html 파일의 내용입니다.
기본 템플릿으로 생성된 코드에서 16 번째 라인부터 35 라인이 추가된 코드 입니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>DotNet6BlazorWebAssemblyAppGroup</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link href="DotNet6BlazorWebAssemblyAppGroup.Client.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<div class="container-fluid"
style="position:fixed;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-size: 400% 400%;
background-image: linear-gradient(45deg, #24a3df 0%, #1430bd 25%, #8c2faf 50%, #e70c5c 100%);">
<div class="row align-items-center" style="height:100%">
<div class="col">
<div>
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Prepare service...
</button>
</div>
</div>
</div>
</div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
실행해보면 처음 접속시 아래와 같이 로딩 메세가 표시되다가 다운로드 후 렌더링이 완료되면 페이지가 표시가 됩니다.
.Net 7 Blazor WebAssembly App
Client 프로젝트의 wwwroot 폴더에 있는 index.html 파일의 내용입니다.
기본 템플릿으로 생성된 코드이며 .Net 6 로 생성된 기본 템플릿과 다르게 17 번째 라인부터 21 라인이 추가되어 있습니다.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<title>DotNet7BlazorWebAssembly</title>
<base href="/" />
<link href="css/bootstrap/bootstrap.min.css" rel="stylesheet" />
<link href="css/app.css" rel="stylesheet" />
<link rel="icon" type="image/png" href="favicon.png" />
<link href="DotNet7BlazorWebAssembly.Client.styles.css" rel="stylesheet" />
</head>
<body>
<div id="app">
<svg class="loading-progress">
<circle r="40%" cx="50%" cy="50%" />
<circle r="40%" cx="50%" cy="50%" />
</svg>
<div class="loading-progress-text"></div>
</div>
<div id="blazor-error-ui">
An unhandled error has occurred.
<a href="" class="reload">Reload</a>
<a class="dismiss">🗙</a>
</div>
<script src="_framework/blazor.webassembly.js"></script>
</body>
</html>
그리고, wwwroot\css\app.css 파일을 보시면 다음과 같이 추가된 css 코드를 확인할 수 있습니다.
.loading-progress {
position: relative;
display: block;
width: 8rem;
height: 8rem;
margin: 20vh auto 1rem auto;
}
.loading-progress circle {
fill: none;
stroke: #e0e0e0;
stroke-width: 0.6rem;
transform-origin: 50% 50%;
transform: rotate(-90deg);
}
.loading-progress circle:last-child {
stroke: #1b6ec2;
stroke-dasharray: calc(3.141 * var(--blazor-load-percentage, 0%) * 0.8), 500%;
transition: stroke-dasharray 0.05s ease-in-out;
}
.loading-progress-text {
position: absolute;
text-align: center;
font-weight: bold;
inset: calc(20vh + 3.25rem) 0 auto 0.2rem;
}
.loading-progress-text:after {
content: var(--blazor-load-percentage-text, "Loading");
}
실행해보면 별도의 추가 코드 없이 처음 접속시 아래와 같이 진행율이 표시되다가 다운로드 후 렌더링이 완료되면 페이지가 표시가 됩니다.
.Net 8 Blazor Web App
Client 프로젝트의 Components 폴더에 있는 App.razor 파일의 내용입니다.
.Net 8 부터는 razor 구문으로 작성이 가능하게 변경되었습니다. 좋네요!
기본 템플릿으로 생성된 코드에서 RenderModeCurrent 변수를 추가해서
rendermode 를 지정하게 수정하고 PreRender 를 false 로 할당합니다.
(초기화 로직에 서버에서 다국어 관련 콘텐츠를 받아서 처리하는 부분을 포함한 서비스 특성상 미리 렌더링 되지 않게 하기 위함입니다.)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<base href="/" />
<link rel="stylesheet" href="bootstrap/bootstrap.min.css" />
<link rel="stylesheet" href="app.css" />
<link rel="stylesheet" href="DotNet8BlazorWebApp.styles.css" />
<link rel="icon" type="image/png" href="favicon.png" />
<HeadOutlet @rendermode="@RenderModeCurrent" />
</head>
<body>
<div id="loadingInit" class="container-fluid"
style="position:fixed;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
background-size: 400% 400%;
background-image: linear-gradient(45deg, #24a3df 0%, #1430bd 25%, #8c2faf 50%, #e70c5c 100%);">
<div class="row align-items-center" style="height:100%">
<div class="col">
<div>
<button class="btn btn-primary" type="button" disabled>
<span class="spinner-border spinner-border-sm" role="status" aria-hidden="true"></span>
Prepare service...
</button>
</div>
</div>
</div>
</div>
<Routes @rendermode="@RenderModeCurrent" />
<script src="_framework/blazor.web.js"></script>
<script>
function DeleteElementById(id) {
var element = document.getElementById(id);
element.parentNode.removeChild(element);
};
</script>
</body>
</html>
@code {
InteractiveWebAssemblyRenderMode RenderModeCurrent => new InteractiveWebAssemblyRenderMode(false);
}
Server 프로젝트의 Routes.razor 파일의 내용입니다.
렌더링이 완료된 후 로딩 레이어를 삭제하는 Javascript function 을 호출합니다.
@inject IJSRuntime JS
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(Layout.MainLayout)" />
<FocusOnNavigate RouteData="@routeData" Selector="h1" />
</Found>
</Router>
@code {
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
await JS.DeleteElementById("loadingInit");
}
}
}
실행해보면 처음 접속시 아래와 같이 로딩 메세가 표시되다가 다운로드 후 렌더링이 완료되면 페이지가 표시가 됩니다.
Github
해당 예제의 소스 코드는 다음 Github repository 를 참조하시면 됩니다.
0 Comments