dev.to

The Grand Unifying Architecture of Frontend

프런트엔드 아키텍처를 하나로 설명하는 모델

글은 프런트엔드 구조를 브라우저의 탐색·조정, 서버의 콘텐츠, 클라이언트의 낙관적 UI 상태라는 세 책임으로 나눕니다. 이 관점으로 HTMX부터 SPA까지를 설명하고, Solid 2.0이 같은 모델 안에서 여러 구조를 표현하는 방법을 제안합니다.

AI 요약

프런트엔드 개발의 오랜 논쟁은 상태를 누가 소유하느냐에 관한 문제라고 글은 설명합니다. 초기 웹에서는 서버가 상태를 관리했고, JavaScript가 등장한 뒤에는 클라이언트 상태가 늘었습니다. 이후 ASP.NET 같은 방식으로 양쪽 상태를 연결하려는 시도도 이어졌습니다. 저자는 React를 HTMX로 교체하는 문제도 이 논쟁의 연장선에 놓고, 서로 다른 아키텍처를 세 가지 책임으로 정리합니다.

세 가지 책임과 데이터 흐름

첫째는 URL과 탐색입니다. 브라우저가 소유하며 사용자의 이동과 요청을 조정합니다. 둘째는 콘텐츠입니다. HTML이든 JSON이든 서버가 권위 있는 원본을 제공하며, 클라이언트가 직접 쓰지 않습니다. 셋째는 사용자에게 빠른 반응을 주는 UI 상태입니다. 진행 중인 작업, 로컬 상태, 낙관적 업데이트가 여기에 해당합니다.

일반적인 흐름은 클라이언트에서 서버로 요청을 보내고, 서버가 콘텐츠를 반환하면 클라이언트가 화면을 정리하는 순서입니다. 글은 쓰기 요청이 탐색·폼·액션 같은 경로를 타고 서버로 올라가고, 서버는 읽기 콘텐츠를 내려보내는 비대칭이 각 부분을 조합하기 쉽게 만든다고 봅니다. 클라이언트가 서버 콘텐츠를 직접 수정하면 서로 다른 두 상태 시스템이 충돌합니다. 낙관적 업데이트는 서버 콘텐츠를 소유하는 방식이 아니라, 확정 전 상태를 잠시 덧씌우는 방식으로 배치합니다.

기존 프레임워크를 같은 틀에 놓기

HTMX는 브라우저 쪽 조정 기능이 작고 HTML이 서버 콘텐츠 대부분을 담당합니다. LiveView는 서버가 처리하는 콘텐츠와 통신 기능을 넓히지만 클라이언트 UI 상태는 제한적입니다. DataStar는 서버에서 채운 Signals를 더해 클라이언트와 가까운 상호작용을 지원합니다. Astro는 탐색, 서버 마크업, 클라이언트 Islands를 구분하고, Next.js Server Components는 여기에 클라이언트 공유 상태를 보존합니다.

React와 JSON API를 쓰는 SPA에서는 클라이언트 상태와 조정 기능이 커지고, 콘텐츠 제공은 JSON API로 분리됩니다. 동기화 엔진 Zero에서는 복제된 저장소를 지속적으로 읽고 클라이언트가 데이터의 로컬 복사본을 둡니다. 저자는 구조별 차이가 표현 가능성보다는 전송 방식, 상태를 유지하는 시간, 클라이언트 코드의 양에 있다고 설명합니다.

Solid 2.0으로 제안하는 구성

글의 뒷부분은 Solid 2.0의 기능으로 세 책임을 조절하는 설계를 제시합니다. 라우터가 별도의 Link 컴포넌트에 의존하지 않고 JSX 컴파일러가 a[href]와 form[action] 요소를 등록합니다. 서버에서 전달한 마크업에도 같은 처리를 적용하므로, 클라이언트 컴포넌트가 없는 HTML도 클라이언트 탐색에 참여합니다. 폼과 버튼은 서버 함수 액션에 연결하며, 무효화된 UI를 한 번의 왕복으로 갱신하는 방식을 설명합니다.

서버 함수는 Seroval로 Promise나 AsyncIterable 같은 비동기 값도 직렬화합니다. 서버에서 값이 바뀌면 반응형 그래프가 관련 결과를 다시 보내고, 클라이언트는 해당 값을 갱신합니다. 이 통신은 기본 Request/Response뿐 아니라 SSE나 소켓 같은 지속 연결에도 적용할 수 있다고 제안합니다. 다만 지속 연결에서 서버의 반응형 그래프는 영속 데이터에서 다시 계산할 수 있는 투영이어야 하며, 서버 프로세스의 세션이나 이벤트 재생 기록이 진실의 원천이 되어서는 안 된다고 강조합니다.

낙관적 상태는 비동기 작업 위에 놓는 임시 예측으로 설명합니다. 작업이 확정되면 실제 값에 맞추고, 실패하면 되돌립니다. 예시에서는 입찰 금액을 먼저 화면에 반영한 뒤 서버에 요청하고, 서버에서 해당 금액이 확인될 때까지 상태를 유지합니다.

저자는 서버 응답이 클라이언트 DOM에 직접 쓰이지 않도록 콘텐츠를 이를 만든 함수와 인자에 해당하는 주소에 저장하는 방식을 제안합니다. 화면은 자신이 구독한 주소의 콘텐츠를 읽습니다. 이 구조에서는 이전 요청의 응답이 다른 화면을 덮어쓰지 않으며, 클라이언트 컴포넌트는 시작 시 한 번만 하이드레이션합니다. 서버 전용 콘텐츠는 HTML이나 데이터 중 한 형태로만 전달해 직렬화 중복도 피한다는 설명입니다.

마지막으로 저자는 Solid 2.0의 Async Signals와 use server를 같은 작성 모델의 기반으로 제시합니다. 서버 마크업 중심 화면부터 SPA, 지속 연결 기반 화면까지 한 애플리케이션 안에서 조합하는 구상입니다. 해당 기능들이 여러 프런트엔드 구조를 표현한다는 것은 글의 주장으로, 댓글에서는 라우트가 바뀐 뒤 늦게 끝나는 변경 요청의 무효화 범위가 어떻게 유지되는지 질문합니다.

dev.to 반응

  • @compoundlabs — 탐색으로 요청을 보낸 서브트리가 이미 교체된 뒤 변경 작업이 끝날 수 있습니다. 그러면 응답이 이전 라우트 이후에도 유지되는 무효화 범위를 가져야 합니다.

원문: dev.to / 번역·요약: Trawling