0. 앞선 글.
언젠가 웹 프로젝트로 그럴듯한 페이지를 만들어보고 싶단 생각을 하곤 했습니다. 그를 위해 틈틈이 React에 대해 공부도 해보고 간단한 페이지도 만들어보고 했지만 이것저것 붙이는 순간 번번이 무너져 내리곤 했습니다.
진짜 React가 맞는가에 대한 고민을 하며 Vue와 Svlte에 대해서도 알아보던 와중 Blazor와 React를 비교한 글이 있어 해당 글을 읽고 번역을 해 남겨둡니다.
만약 여러분이 C#을 어느 정도 할 줄 알고 아직 웹 프레임워크를 선택하지 않았다면 이 글이 약간이나마 도움이 될 수 있기를 바랍니다.
이 글은 다음 글을 번역한 글입니다: React vs. Blazor: Minimize JavaScript in your SPAs
1. SPA에서 JavaScript 최소화 하기.
SPA(단일 페이지 애플리케이션, Single Page Application)을 구축할 때 개발자가 선택할 수 있는 몇 가지 프레임워크가 있습니다. 가장 있기 있는 세 가지 프레임워크는 Angular, React, Vue입니다. 하지만 이 세 프레임워크를 사용해 SPA를 구축하려면 JavaScript가 필요합니다.
개발자가 SPA를 만드는데 관심이 있지만 JavaScript의 문제들을 처리하고 싶지 않다면 어떻게 해야 할까요? 이 글에서는 JavaScript를 최소화하기 위한 두 가지 다른 클라이언트 측(client-side) 옵션인 React와 Blazor를 살펴보고 그 기능을 비교합니다. 이제 시작해 봅시다.
2. Blazor가 뭔가요?
Blazor는 C# dotNet과 WebAssembly를 활용하여 그 고유한 방식을 따라 웹 브라우저에서 실행되는 SPA를 만드는 Microsoft UI 프레임워크입니다. 기본적으로 Blazor를 사용하면 개발자가 HTML, CSS, C#을 사용해 대화형 클라이언트 측 애플리케이션을 빌드할 수 있습니다.
반면에 React는 유저 인터페이스와 UI 컴포넌트를 빌드하기 위한 선언적이고 효율적이며 유연한 JavaScript 라이브러리입니다. React와 Blazor는 풍부하고 대화형을 지원하면서 현대적인 클라이언트 측 애플리케이션을 구축하기 위한 프레임워크와 라이브러리라는 유사성을 갖고 있습니다.
Blazor의 고유한 기능 중 하나는 JavaScript의 상호 운용성입니다. 즉 Blazor앱은 dotNet 메서드에서 JavaScript 함수를 호출하고 JavaScript 함수에서 dotNet 메서드를 호출할 수 있습니다.
Blazor는 클라이언트 측 Blazor WebAssembly와 서버 측 Blazor Server의 두 가지 주요 프로젝트로 구성됩니다. Blazor 서버 구현은 보다 전통적인 dotNet 앱 접근 방식을 사용하며 서버가 메시지 전달을 위해 SignalR을 사용해 프런트엔드로 연결이 필요합니다. 반면 Blazor WebAssembly는 프로젝트를 배포 가능한 정적 번들로 패키징 합니다. 이 글에서는 Blazor WebAssembly와 React를 비교하는데 초점을 둡니다.
3. Blazor Wasm(WebAssembly)
Blazor Wasm은 Xamarin Mono 프레임워크의 컴파일된 버전과 함께 실행됩니다. 최종 결과는 실제 브라우저에서 직접 dotNet C# 애플리케이션을 실행할 수 있습니다. Blazor는 dotNet 코드를 Wasm으로 컴파일 한 다음 정적 번들로 배포할 수 있습니다. 오래된 브라우저의 경우 Blazor는 asm.js를 사용해 브라우저가 지원하는 공통 프레임워크로 컴파일합니다.
Blazor는 JavaScript 라이브러리와 상호 운용성을 지원합니다. npm 모듈을 빌드와 함께 가져와 Blazor 프로젝트와 함께 사용할 수 있습니다. C# 코드와 JavaScript 패키지에 직접 상호작용 하기 위해 Blazor는 IJSRuntime in C# 및 IJSRuntime을 제공합니다. 자세한 설명은 Microsoft의 문서를 확인하시기 바랍니다.
4. 폴더 구조.
Blazor 앱과 React 앱을 모두 만들어보고 기본적으로 무엇이 있는지 비교해 보겠습니다. 새 Blazor 프로젝트를 만들려면 dotNet SDK를 다운로드해 설치하고 터미널에서 다음 명령어를 실행해야 합니다.
dotnet new blazorwasm -n BlazorApp
blazorwasm 명령은 WebAssembly로 새로운 Blazor 프로젝트를 생성한다는 의미입니다. -n 플래그는 프로젝트 이름을 의미합니다.
program.cs 파일에는 WebAssembly 앱을 시작하고 실행하는데 필요한 주요 메서드가 포함되어 있습니다.
또한 앱을 마운트하고 앱 ID가 있는 태그를 선택합니다. HTTP 클라이언트는 종속성 주입을 사용해 로드되고 Blazor 앱의 HTTP 모듈은 JavaScript Fetch API를 기반으로 빌드됩니다.
React 앱에서 index.js는 Blazor 앱의 program.cs와 유사합니다. 아래 코드 스니펫에서 React DOM은 앱 구성요소를 렌더링하고 루트 구성요소로 ID가 root인 요소를 선택합니다.
5. 프로그래밍 언어.
Blazor는 JavaScript 대신 C#을 프로그래밍 언어로 사용해 dotNet 라이브러리의 기존 dorNet 에코시스템을 활용합니다. 이 기능을 통해 C# 개발자는 C#을 사용해 백엔드 코드를 작성하는 것을 시작으로 C#을 사용해 웹 및 모바일 애플리케이션을 구축하는 풀 스택까지 기술을 확장할 수 있습니다.
처음에는 이 C#이 JavaScript 개발자에게 자연스럽지 않을 수 있지만 C#을 잘 이해하면 완전히 C#으로 작성된 강력한 풀 스택 애플리케이션을 빌드할 수 있습니다.
React는 JavaScript를 프로그래밍 언어로 사용합니다. 기본적으로 웹 개발자는 가장 익숙한 언어를 사용할 수 있습니다. 또한 React Native를 사용하면 동일한 코드를 공유하는 웹, 안드로이드, iOS 애플리케이션을 구축할 수 있습니다.
6. 템플릿
React로 SPA를 생성할 때 Create React App 툴 체인 사용을 권장합니다. Create React App 툴 체인은 기본적으로 JavaScript용 구문 확장인 JSX로 구성된 React 앱으로 초기화합니다. JSX는 React에서 HTML을 작성하고 HTML로 JavaScript를 작성할 수 있게 해주는 템플릿 엔진처럼 동작합니다.
Blazor는 수년간 사용되어 온 Razor 템플릿 엔진을 사용합니다. 이 템플릿 엔진은 C#과 ASP.NET 에코시스템에서 새로운 것이 아닙니다. 이 엔진은 C#과 ASP.NET을 사용해 웹 페이지에 서버 측 코드를 포함하는 데 사용됩니다.
JSX처럼 Razor 템플릿 엔진을 사용하면 마크업에 C# 코드를 작성할 수 있습니다.
7. 성능.
Blazer 프로젝트는 브라우저에서 필요한 DLL 라이브러리와 전체 dotNet 런타임을 다운로드해야 하므로 더 느립니다. 또한 Blazor 앱에는 대기시간에 문제가 있습니다. 따라서 전 세계 사람들이 액세스 할 수 있는 웹 애플리케이션을 구축하는 경우에 Blazor는 가장 적합한 프레임워크가 될 수 없습니다.
위 다이어 그램에서 Lighthouse 점수는 Blazor앱에 몇 가지 심각한 성능 문제가 있음을 보여줍니다. 초기 페이지 로드 시 필요한 종속성을 다운로드해야 하므로 초기 페이지 로드 시간이 느립니다.
이 부분에 대해서 React가 빛을 발합니다. UI 라이브러리로서 React 핵심 패키지는 매우 간결합니다. 구성 요소 기반 패러다임을 사용해 놀랍도록 빠르고 현대적인 클라이언트 측 애플리케이션을 구축하기 위해 완전히 최적화되어 있습니다.
8. 생태계.
이 글을 쓰는 시점에서 Microsoft는 Blazor WebAssembly 및 Blazor Server를 포함해 4개의 새로운 Blazor 에디션을 발표했습니다.
반면에 React 생태계는 구현하려는 거의 모든 것에 대한 패키지를 npm에서 찾을 수 있을 정도로 매우 큽니다. React는 Facebook의 전폭적인 지원을 받으며 클라이언트 측 애플리케이션이 구축되는 방식이 많이 바뀌었기 때문에 커뮤니티에서 많은 지원을 받았습니다. 또한 React는 여전히 JavaScript이기 때문에 웹 개발자에게 익숙합니다.
React의 판매 가치는 "한번 배워서 어디서나 사용"입니다. 기본적으로 React, React DOM, React Native를 사용하면 고도화되고 풍부한 대화형 프런트엔드 웹, 안드로이드, iOS 애플리케이션을 구축할 수 있습니다. 이는 대부분의 회사가 React와 React Native에 능숙한 개발자를 고용해 비교적 저렴한 비용으로 견고한 제품과 플랫폼을 쉽게 구축할 수 있도록 합니다.
9. GitHub 평가.
이 글을 작성하는 시점에 React는 GitHub에서 188,000개 이상의 별을 받았습니다. 틀림없이 일반적으로 가장 사랑받는 JavaScript 라이브러리 중 하나입니다. 한편 Blazor는 GitHub에서 약 28,000개의 별을 받았습니다.
Blazor가 2018년도에 처음 출시되었고 이 글을 시점에서 개발자 커뮤니티 내에서 비교적 새롭다는 사실을 감안하면 타당한 이유가 된다고 생각합니다.
10. PWA(Progressive Web App) 지원.
Blazor PWA는 개발자가 고급 Progressive Web App을 빌드할 수 있도록 지원합니다. React 애플리케이션에서 PWA 지원을 추가하는 것은 아주 쉽습니다. 다음 명령을 실행하면 서비스 워커 파일이 추가된 React 앱이 초기화됩니다.
npx create-react-app my-app --template cra-template-pwa
11. Blazor Native와 Blazor Hybrid vs. React Native
이 글을 작성하는 당시 실험적인 Blazor Native를 사용하면 기본적으로 개발자가 Mobile Blazor 바인딩을 사용해 Blazor로 모바일 앱을 빌드할 수 있습니다. C#과 dotNet을 사용해 Blazor로 안드로이드와 iOS 앱을 개발하는 것은 실제로 가능합니다.
Blazor Hybrid 앱은 단일 앱에 기본 UI와 웹 UI를 결합한 것입니다. Blazor를 사용하면 앱의 기본 UI를 작성하고 앱에 웹 UI를 만들 수 있으므로 Blazor를 사용해 웹과 모바일 앱 모두 빌드할 수 있습니다. 기본적으로 웹과 모바일 앱에서 코드 스니펫을 공유합니다. 이는 확실히 C# dotNet 개발을 하기 좋은 타이밍입니다.
React는 React Native를 사용하여 네이티브 모바일 앱을 빌드하므로 React 개발자가 React로 모바일 앱을 빌드할 수 있습니다. React Native를 사용하면 기본 UI 컨트롤을 사용하며 기본 플랫폼에 대한 전체 액세스 권한을 가질 수 있습니다.
React Native는 프로덕션 단계에서 사용되지만 Blazor Native는 아직 개발 단계에 있습니다. React Native와 비교할 때 Blazor Native는 커뮤니티 지원이 부족합니다.
12. 패키지 관리자.
다른 JavaScript 프레임워크나 라이브러리와 마찬가지로 React는 종속성을 관리하기 위한 패키지 관리자로 npm과 Yarn을 사용합니다. Blazor WebAssembly앱에서는 다음 방법 중 하나로 패키지를 손쉽게 설치할 수 있습니다: PackageReference, dotNET CLI, Package manager, Paket CLI.
PackageReference를 사용해 패키지를 설치하려면 Balzorize.csproj 파일로 이동해 ItemGroup 태그 내에 다음과 같이 패키지를 추가합니다:
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
dotNET CLI를 사용해 패키지를 설치하려면 터미널에서 앱의 루트 디렉터리로 이동하고 다음 명령을 실행합니다:
dotnet add package Microsoft.AspNetCore.Blazor.HttpClient --version 3.2.0-preview3.20168.3
dotNET CLI 및 Paket CLI에 대해 알아보려면 가이드를 확인하시기 바랍니다.
13. 구성요소 간의 통신.
기본적으로 React는 구성요소의 상태를 처리하기 위해 두 가지 주요한 접근 방식을 제공합니다. 구성요소는 자체 상태나 데이터를 처리하거나 props를 통해 데이터를 받을 수 있습니다. HTTP 섹션에서 구성요소가 자체 상태를 처리하는 방법을 확인할 수 있습니다.
다음은 구성요소가 React 앱의 상위 구성요소에서 props를 통해 데이터를 받는 방법의 예시입니다:
// Parent Component
export default function Blog() {
const blogPosts = [
{
id: 1,
title: 'This is the title',
content: 'This is some random content',
},
//...
{
id: 4,
title: 'This is the title',
content: 'This is some random content',
},
]
return (
<>
<BlogCard blogPosts={blogPosts}/>
</>
)
}
블로그 게시물을 포함하는 각 객체의 배열인 blogPosts를 하위 구성요소인 BlogCard 구성요소에 다음과 같이 전달합니다:
// Child Component
export default function BlogCard( { blogPosts } ) {
return (
<>
{blogPosts.map(blogPost => (
<div className="blog-post" key={blogPost.id}>
<h1>{blogPost.title}</h1>
<p>{blogPost.content}</p>
</div>
))}
</>
)
}
이제 하위 구성요소인 BlogCard를 렌더링 할 때 props를 통해 블로그 게시물 목록을 받아올 수 있습니다. React의 props에 대해 더 자세히 알아보려면 공식 문서를 확인해 주시기 바랍니다.
Blazor에서 자식 구성요소는 다음과 같이 매개변수를 통해 부모 구성요소에서 데이터를 받아옵니다:
// Child Component
<h2>@Title</h2>
<p>@Content</p>
@code {
// Demonstrates how a parent component can supply parameters
[Parameter]
public string Title { get; set; }
[Parameter]
public string Content { get; set; }
}
BlogCard 구성요소를 렌더링 할 때 제목과 콘텐츠를 전달할 수 있으며 다음과 같이 렌더링 됩니다:
<BlogCard Title="What is Blazor?" Content="Blazor is a web UI framework using C#/Razor and HTML..." />
14. 라우팅.
React 애플리케이션에서 라우터는 미리 구성되거나 설치되지 않습니다. React Router 패키지는 대부분 클라이언트 측 탐색을 구현하는 데 사용됩니다.
문서에 따르면 React Router는 React Native 프로젝트를 포함하여 React가 렌더링 되는 모든 곳에서 작동합니다. API는 정말 간단하지만 URL 매개변수, 구성요소 리디렉션, 지연 로딩, 페이지 전환, 중첩 라우팅 등과 같은 많은 강력한 기능을 처리합니다.
React 앱에서 라우팅을 설정하려면 일반적으로 react-router-dom 패키지를 설치하고 React Router DOM 패키지의 브라우저 라우터 모듈을 사용해 index.js에 전체 앱을 래핑 합니다. 그런 다음 App.js 구성요소에서 React Router DOM의 경로 모듈을 사용해 페이지를 렌더링 합니다.
다음 이미지는 React에서 라우팅이 동작하는 방식을 보여줍니다:
Blazor WebAssembly 클라이언트 측 애플리케이션에서 라우팅 시스템은 ASP.NET의 기존 라우팅 엔진에 의존합니다. @page 지시문을 사용하고 파일 맨 위에 연결하려는 경로를 사용하여 Blazor 구성요소에 대한 경로를 매핑할 수 있습니다.
다른 페이지로 이동하려면 react-router-dom에서 NavLink 구성요소가 작동하는 방식과 유사한 NavLink 구성요소를 사용해야 합니다.
다음 코드를 사용해 파일 맨 위에 NavigationManager를 넣어 Blazor 앱의 페이지를 탐색합니다.
@inject NavigationManager NavManager
그런 다음 아래와 같이 주입한 NavManager의 NavigateTo 메서드를 호출합니다:
@inject NavigationManager NavManager
<p>Learn more about us</p>
<button @onclick="navigateHome">Go back home</button>
@code {
private void navigateHome()
{
NavManager.NavigateTo("");
}
}
15. HTTP
Blazor 애플리케이션에서 HTTP 요청을 다루는 법에 대해 알아보기 위해서 페이지 디렉터리에 FetchPost.razor 파일을 만듭니다:
@page "/http"
@inject HttpClient Http
<h1>Blog post</h1>
@if (posts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Title</th>
<th>Body</th>
</tr>
</thead>
<tbody>
@foreach (var post in posts)
{
<tr>
<td>@post.title</td>
<td>@post.body</td>
</tr>
}
</tbody>
</table>
}
@code {
private BlogPost[] posts;
protected override async Task OnInitializedAsync()
{
posts = await Http.GetJsonAsync<BlogPost[]>("https://jsonplaceholder.typicode.com/posts");
Console.WriteLine(posts);
}
public class BlogPost
{
public int id { get; set; }
public String title { get; set; }
public String body { get; set; }
}
}
이 코드에서 세 가지 일이 일어나고 있습니다. 먼저 HTTP 클라이언트를 사용해 HTTP 호출을 수행하는데 도움을 주는 서비스인 HttpClient를 주입합니다. Blazor 3.1.0 버전부터 Blazorize.csproj 파일에 Blazor HTTP 클라이언트를 추가해야 합니다.
그리고 GetJsonAsync() 메서드를 사용하여 HttpClient를 호출해 정의된 엔드포인트에서 JSON을 가져옵니다. 마지막으로 가져온 JSON을 기반으로 BlogPost 결과를 만듭니다.
HttpClient를 주입하려면 상단에 @inject HttpClient Http를 추가해야 합니다. 데이터를 능동적으로 가져오기 위해 HttpClient를 호출합니다. 페이지가 초기화될 때 실행이 보장되는 수명 주기 메서드인 OnInitializedAsync()를 정의하고 이를 수행합니다.
React와 같은 라이브러리를 사용하는 이점 중 하나는 도구의 유연성입니다. React는 Blazor와 같은 HTTP 클라이언트를 제공하지 않습니다. React 개발자는 Fetch API, Axios, XHR을 사용해 HTTP 요청을 할 수 있습니다.
여기서 HTTP 요청의 경우 JavaScript Fetch API를 사용합니다. 아래 코드는 내장 JavaScript Fetch API를 사용해 React 앱에서 간단한 HTTP 요청을 만드는 방법을 보여줍니다:
// post.js
import React, { useState, useEffect } from 'react'
export default function Post() {
const [posts, setPosts] = useState([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch("https://jsonplaceholder.typicode.com/posts")
.then(response => response.json())
.then(post=> {
setPosts(post)
setLoading(false)
})
}, [])
return (
<div>
{
loading ?
(
<p>Loading...</p>
) : (
posts.map((post, i) => (
<div>
<p>{post.title}</p>
<p>{post.body}</p>
</div>
))
)
}
</div>
)
}
useEffect Hook에서 엔드포인트를 호출하고 있는 것에 주목하시기 바랍니다. React는 렌더링 후 구성요소가 API에서 데이터를 가져와야 한다고 알려줍니다. 그런 다음 요청이 성공하면 setPosts를 호출하고 API에서 post 객체를 전달해야 합니다. React에서 userState Hooks가 작동하는 방식에 대한 자세한 내용은 공식 문서를 확인해 주시기 바랍니다.
16. 결론.
SPA를 구축하기 위한 최상의 프런트엔드 프레임워크를 선택하는 것은 팀 내 선호도, 에코시스템, 성능, 확장성을 포함한 많은 요인에 따라 달라집니다. 이 글에서는 React와 Blazor를 비교해 이 두 가지 멋진 프레임워크가 어떻게 작동되고 있는지 확인해 보았습니다.
React와 Blazor는 몇 가지 면에서 유사하며 동일한 작업을 수행하는 데 사용할 수 있습니다. 그렇다면 어떤 것을 선택해야 할까요? 인기도, 구축 중인 프로텍트 우형, 확장성, 유지 관리 가능성 등 다양한 요인을 고려해야 합니다.
이 글을 통해 다음 프로젝트를 위한 프런트엔드 프레임워크를 선택할 때 도움이 되었길 바랍니다. 즐거운 코딩 되세요.
'Programming' 카테고리의 다른 글
API Gateway의 컨셉: API Gateway란? (1) | 2022.10.19 |
---|---|
Blazor Server vs Blazer WebAssembly: Blazor 호스팅 모델의 차이점 (0) | 2022.09.22 |
[FTP] vsftpd TLS 설정 (0) | 2022.09.15 |
[Git] Windows에서 Git 사용 시 Fatal: unsafe repository. is owned by someone else. 에러 해결 방법. (0) | 2022.07.27 |
[Git] The server's host key is not cached. 오류 해결 방법. (0) | 2022.07.27 |