[Web] Preact와 Vite를 활용한 설문지 개발

반응형

안녕하세요, 오늘은 최근에 제가 Flutter 웹앱으로부터 설문 기능을 분리하여 Preact와 Vite, TypeScript를 활용해 개발한 경험을 공유하려고 합니다.

문제! 문제! Flutter 웹앱의 한계와 트래픽 급증으로 인한 성능 이슈

저희 회사는 Flutter를 사용하여 CSR(Client-Side Rendering) 방식으로 개발된 웹앱을 운영하고 있었습니다.

Flutter는 멀티플랫폼 지원이라는 큰 장점이 있지만, 웹 환경에서는 몇 가지 심각한 한계점을 지니고 있습니다. 특히 웹 배포 방식에 관련된 문제가 저희 프로젝트에서 큰 도전으로 다가왔습니다.

 

Flutter 웹앱의 가장 큰 단점 중 하나는 배포 아키텍처입니다. Flutter 웹은 새로운 버전이 배포될 때마다 사용자가 전체 애플리케이션을 다시 다운로드해야 하는 구조입니다. 작은 변경사항이 있더라도 사용자는 전체 앱 번들을 다시 받아야 하죠. 이는 일반적인 웹 애플리케이션의 부분 업데이트 방식이나 효율적인 캐싱 전략의 이점을 살리지 못하는 구조입니다.

 

이러한 Flutter 웹의 한계는 평소에는 큰 문제가 되지 않았습니다. 저희 앱은 특정 유저를 위한 사이트라서 평균적인 사용자는 일별로 약 1,500~2,000명 정도였기 때문에 서버와 네트워크 인프라가 이 정도 규모는 충분히 처리할 수 있었습니다. 그러나, 저희 앱에 내장된 설문 기능이 문제였습니다.

 

저희 유저가 설문을 만들어서 설문을 배포할 수 있는데 배포한 설문지를 응답하는 기능 역시 현재 배포한 앱 내부에 넣었습니다. 사실, 미리 발생할 수 있는 문제에 대해 생각했어야 됐는데... 그게 말처럼 쉽지가 않죠.

 

1,500명 내외가 사용하는 앱이 갑자기 20,000명 가까이 동시접속자가 늘어버리는... 그래서 각 사용자가 앱에 접속할 때마다 수 MB 크기의 전체 Flutter 웹앱을 다운로드해야 했고, 이는 서버의 대역폭에 엄청난 부담을 주었습니다.

 

본질적으로 이 문제는 대역폭 병목 현상이었습니다. 20,000명의 사용자가 동시에 전체 앱을 다운로드하려고 시도하면서 서버의 네트워크 대역폭이 포화 상태에 이르렀고, 이로 인해 다운로드 속도가 현저히 떨어졌습니다. 결과적으로 사용자들은 긴 로딩 시간을 경험하게 되었고,

일부 사용자는 타임아웃으로 인해 앱에 접속조차 할 수 없었습니다.

 

더 심각한 문제는 이러한 대역폭 문제가 설문 기능뿐만 아니라 전체 앱의 성능에 영향을 미쳤다는 점입니다. 핵심 서비스를 이용하려는 기존 사용자들도 느린 로딩 시간과 응답 지연을 경험했고, 이는 사용자 경험 저하로 이어졌습니다.

 

그래서, 핵심 서비스에 더 이상 영향을 주지 않으면서도 이 문제를 해결하기 위해, 트래픽이 집중되는 설문 기능만을 분리하여 별도의 웹 애플리케이션으로 개발하기로 결정했습니다. 이러한 마이크로 프론트엔드 접근 방식은 전체 시스템의 확장성과 성능을 개선하는 데 중요한 전략이었습니다.

기술 스택 선택: Preact + Vite + TypeScript

설문 기능을 분리하면서 어떤 기술 스택을 사용할지 많은 고민을 했습니다. 결국 Preact, Vite, TypeScript의 조합을 선택했는데, 그 이유를 자세히 설명해 드리겠습니다.

1. Preact를 선택한 이유

Preact는 React의 경량화 버전이라고 합니다. 사실 저도 이번에 처음 알았습니다..

Preact는 기존 React의 핵심 기능을 유지하면서도 불필요한 기능을 제거하여 번들 크기를 크게 줄인 라이브러리입니다.

저희 설문 기능은 복잡한 상태 관리나 고급 기능이 필요하지 않았기 때문에 Preact면 적합할 것이라고 생각했습니다.

Preact의 특징과 장점에 대해서 자세하게 한번 살펴보겠습니다.

Preact의 기술적 특징과 장점

작은 번들 크기

Preact는 약 3KB(gzip 압축 시)의 크기로, 일반 React(약 40KB)에 비해 30-40% 가량 번들 크기가 감소합니다. 이는 초기 로딩 시간을 크게 개선하며, 특히 모바일 환경이나 느린 네트워크 상황에서 사용자 경험을 향상시킵니다. 실제로 우리 프로젝트에서는 Preact 도입 후 초기 로딩 시간이 평균 1.7초에서 0.9초로 약 47% 감소했습니다.

 

빠른 렌더링 성능
Preact는 Virtual DOM 알고리즘을 최적화하여 React보다 더 빠른 렌더링 성능을 제공합니다. 특히 메모리 사용량이 React의 약 1/3 수준으로, 리소스 제약이 있는 환경에서 더 효율적으로 작동한다고 합니다.

 

React와의 호환성과 유사성
Preact는 React의 API를 거의 그대로 유지합니다. 그래서 React에 익숙하면 쉽게 개발할 수 있었습니다. preact/compat이라는 호환성 레이어를 통해 대부분의 React 라이브러리를 그대로 사용할 수 있습니다. 제가 그래도 어느정도 React에 익숙했기 때문에 추가적인 학습 비용 없이 빠르게 개발할 수 있었습니다.

2. Vite를 선택한 이유

Vite는 Vue.js 창시자인 Evan You가 만든 최신 프론트엔드 개발 도구로, 프랑스어로 '빠르다'를 의미합니다. 이 이름처럼, Vite는 개발 서버 구동 속도와 빌드 성능에 초점을 맞추고 있습니다. 특히 기존의 번들러와는 다른 접근 방식을 취하고 있어 주목받고 있습니다.

Vite의 핵심 특징

번들링 없는 개발 서버

Vite는 개발 모드에서 ESM(ES Modules)을 기반으로 동작합니다. 브라우저에서 기본적으로 지원하는 ES 모듈 시스템을 활용하여, 번들링 과정 없이 필요한 모듈만 요청 시 로드합니다. 이는 프로젝트 규모와 관계없이 항상 빠른 서버 시작 속도를 제공합니다.

 

esbuild 기반의 사전 번들링

개발 시작 단계에서 node_modules의 의존성을 esbuild를 통해 사전 번들링합니다. Go로 작성된 esbuild는 JavaScript 기반 번들러보다 10-100배 빠른 속도를 제공합니다. 이런 방식으로 기존 JavaScript 코드에 대해 빠른 번들링을 수행하면서도, 개발자가 작업하는 코드는 ESM 방식으로 제공하여 최적의 개발 경험을 제공한다고 합니다.

 

HMR(Hot Module Replacement)

코드 변경 시 전체 페이지를 새로고침하지 않고 변경된 모듈만 교체합니다. 이 과정이 매우 빠르게 이루어져 개발 생산성을 크게 향상시키는데, Flutter 에 익숙한 저도 불편함을 느끼지 못할 만큼의 속도였습니다.

 

최적화된 프로덕션 빌드

개발 모드와 달리, 프로덕션 빌드 시에는 Rollup을 사용하여 최적화된 번들을 생성합니다. Rollup은 코드 분할, 트리 쉐이킹 등 최적화 기능을 제공하여 최종 번들 크기를 최소화합니다. 최종적으로 만들어진 설문지 프로젝트는 150kb라는... 놀라운 용량을 자랑했습니다?

Webpack과의 비교

웹팩(Webpack)은 현재까지 가장 널리 사용되는 번들러이지만, 대규모 프로젝트에서는 빌드 속도가 느려지는 문제가 있습니다. 이는 웹팩의 번들링 방식 때문인데, 모든 모듈을 하나의 번들로 만들어 제공하는 과정에서 발생하는 병목 현상입니다.

 

반면 Vite는,

  • 개발 서버 시작 시 모든 파일을 번들링하지 않고, 필요한 파일만 요청 시 변환하여 제공합니다.
  • 사용자가 방문하지 않은 페이지의 코드는 처리하지 않아 리소스를 절약합니다.
  • 변경된 파일과 그 의존성만 다시 로드하여 개발 속도를 크게 향상시킵니다.

실제로 대규모 프로젝트에서는 Webpack에 비해 개발 서버 시작 속도가 20~30배 이상 빠르며, 코드 수정 후 반영 속도도 수 초에서 수십 밀리초로 단축된다고 합니다.

3. TypeScript를 선택한 이유

TypeScript는 개발 생산성과 코드 품질을 높이는 데 큰 도움이 되었습니다.

  • 타입 안전성: 설문 데이터와 같은 중요한 정보를 다룰 때 타입 오류를 사전에 방지할 수 있었습니다.
  • 개발자 경험: 자동 완성과 타입 추론을 통해 더 빠르고 정확하게 코드를 작성할 수 있었습니다.
  • 유지보수성: 코드의 의도가 명확히 드러나 팀원 간 협업과 향후 유지보수가 용이해졌습니다.
  • 리팩토링 용이성: 타입 시스템의 도움으로 대규모 리팩토링도 안전하게 수행할 수 있었습니다.

개발 과정과 결과

설문 시스템 개발은 크게 다음과 같은 단계로 진행되었습니다.

  1. 프로젝트 초기화: Vite의 TypeScript + Preact 템플릿을 사용하여 프로젝트를 시작했습니다.
  2. npm create vite@latest survey-app -- --template preact-ts
  3. 설문 컴포넌트 설계: 재사용 가능한 설문 컴포넌트를 설계하고 구현했습니다. 이 과정에서 Preact의 경량화된 특성이 큰 도움이 되었습니다.
  4. API 연동: 기존 백엔드 API와 연동하여 설문 데이터를 주고받을 수 있도록 구현했습니다.
  5. 최적화: Vite의 빌드 최적화 기능을 활용하여 최종 번들 크기를 최소화했습니다.
  6. 배포: 독립적인 서버에 설문 애플리케이션을 배포하고, 메인 앱에서 링크를 통해 접근할 수 있도록 설정했습니다.

그리고 결과적으로,

  • 로딩 시간 70% 감소: 기존 Flutter 앱 내 설문 페이지보다 초기 로딩 시간이 70% 이상 감소했습니다.
  • 서버 부하 분산: 메인 앱 서버의 부하가 크게 줄어들어 전체 시스템의 안정성이 향상되었습니다.
  • 사용자 경험 개선: 더 빠른 응답 시간과 부드러운 인터랙션으로 설문 완료율이 15% 증가했습니다.

이번 프로젝트를 통해 Preact, Vite, TypeScript의 조합이 특히 경량화가 필요한 웹 애플리케이션 개발에 얼마나 효과적인지 체감할 수 있었습니다. 특히 트래픽이 많은 기능을 분리하여 최적화된 기술 스택으로 재구현하는 접근 방식은 전체 시스템의 성능과 안정성을 크게 향상시킬 수 있다는 점을 배웠습니다.

 

앞으로도 각 기능의 특성과 요구사항에 맞는 최적의 기술 스택을 선택하고, 모노리틱 아키텍처에서 필요에 따라 기능을 분리하는 유연한 접근 방식이 중요하다고 생각합니다. Preact와 Vite는 특히 성능이 중요한 마이크로 프론트엔드 개발에 매우 좋은 선택이 될 수 있을 것입니다.

 

Designed by JB FACTORY