HTMX 대신 직접 만든 SSR 라이브러리로 플레이어 상태 유지
자체 호스팅 팟캐스트 앱 서버를 SvelteKit에서 DinoSsr(DinoSsr)로 리팩토링하며 서버 사이드 렌더링(Server-Side Rendering) 중심 아키텍처로 전환함
팟캐스트 재생 중 페이지 네비게이션 시 오디오 플레이어 상태 유실 문제를 해결하기 위해 HTMX(HyperText Markup eXtensions) 도입을 시도함
HTMX의 핵심 기법인 last-modified/if-modified-since 헤더, pushState/popstate, 요소 추출 및 치환 기능을 직접 구현하여 맞춤형 SSR 라이브러리(Custom SSR Library)로 대체함
**hx-* 속성 사용 선호도**(data-* 대신)와 인라인 JavaScript 한계 등 HTMX의 단점을Criticisms로 언급하며 프론트엔드 JavaScript 과도기(Frontend JavaScript Fatigue) 문제 제기함
HTMX의 핵심 동작 원리: HTTP 헤더 기반 캐싱 메커니즘
본문에서는 HTMX의 요청/응답 헤더 관리 방식을 직접 구현하며 핵심 동작 원리를 파악했다.
Last-Modified / If-Modified-Since: 서버가 리소스의 최종 수정 시각을 전달하면, 브라우저는 이후 요청 시 조건부 요청을 통해 변경이 없을 경우 304 Not Modified 응답을 받는다. 이 메커니즘으로 불필요한 데이터 전송을 방지한다.
Cache-Control: HTMX는 HTTP 캐싱 헤더를 정밀하게 제어하여 SPA 환경에서도 CDN 캐시를 활용할 수 있다. 이는 React/Vue의 클라이언트 사이드 라우팅이 항상 새로운 번들을 다운로드해야 하는 점과 대비된다.
요소 선택적 갱신: 전체 페이지를 새로고침하는 대신 특정 HTML 요소(예: `<main>` 태그)만 교체하므로 파싱 비용과 레이아웃 재계산을 최소화할 수 있다.
결론적으로 HTMX는 순수 HTTP 시맨틱스를 활용하여 브라우저의 내장 캐시 인프라를 최대한 활용하는 설계다.
SPA vs MPA: 히스토리 관리와 네비게이션 패턴 비교
저자는 SvelteKit의 자동 클라이언트 사이드 라우팅(Client-Side Routing)을 포기하고, 직접 pushState/popstate API를 활용한 네비게이션을 구현했다.
History API 활용: `history.pushState()`로 URL만 변경하고 페이지 리로드를 유발하지 않으며, `popstate` 이벤트 리스너로 브라우저 뒤로가기/앞으로가기 버튼 동작을 감지하고 처리한다. 이 패턴은 최소한의 브라우저 API로 SPA-like 경험을 구현한다.
사전 로딩(Preloading) 전략: HTMX의 preload 익스텐션에서 영감을 받아, pointerdown/pointerenter 이벤트 발생 시 클릭 이전에 이미 fetch 요청을 시작하는 스펙ulative 실행(Speculative Execution) 기법을 적용했다. 이는 인지 지연(Perceived Latency)을 효과적으로 줄인다.
Trade-off: 저자도 인정하듯, 이 접근법은 주소 표시줄 URL과 실제 DOM 상태의 동기화를 개발자가 직접 관리해야 하며, 복잡한 라우팅 시나리오에서는 상태 관리(State Management) 부담이 증가한다.
프론트엔드 JavaScript 과도기의 아키텍처적 함정
본 글은 React/Vue/Angular 생태계에서 서버 사이드 렌더링(Server-Side Rendering)으로의 회귀를 지적했다.
중복 책임(Overlapping Responsibility) 문제: 템플릿과 컴포넌트는 서버 사이드에서 충분히 재사용 가능하며, 이를 브라우저에서도, 특히 브라우저에만 존재하도록 구현하는 것은 복잡성 불균형(Complexity Imbalance)을 초래한다. 저자는 이를 "프론트엔드 JavaScript 피로감(Frontend JavaScript Fatigue)"으로 표현했다.
HTMX의 한계 인식: 저자는 HTMX가 완전한 React 대체재(React Replacement)가 아님을 명확히 인지하고 있다. HTMX는 간단한 증강(Progressive Enhancement)에 적합하지만, 복잡한 상태 관리(State Management)나 실시간 인터랙션(Real-time Interaction) 시 한계가 드러난다.
DinoSsr 선택의 근거: 저자가 자체 개발한 DinoSsr는 정적 사이트 생성(Static Site Generation)과 동적 SSR(Dynamic SSR)을 단일 프레임워크에서 처리하며, 이는 다양한 렌더링 전략(Multi-Stage Rendering)을 필요로 하는 프로젝트에 유리하다.
hx-* 속성 vs data-* 속성: 웹 표준 준수 논쟁
저자는 HTMX의 **hx-* 네이밍 컨벤션**에 대한 미묘한 불만을 표명했다.
hx-select, hx-get, hx-post 등 HTMX 전용 속성은 HTML 표준 속성이 아니므로 호환성 도구(Accessibility Tools, Linters)에서 경고를 발생시킬 수 있다. 반면 **data-* 속성은 HTML5 명세에 공식 포함되어 있어 검증 도구(Validation Tools)**와의 충돌이 적다.
기술적 차이: `data-*` 속성은 JavaScript의 `element.dataset` API로 접근 가능하지만, HTMX는 자체 파서를 통해 `hx-*` 속성을 직접 읽어들인다. 이는 커스텀 네임스페이스(Custom Namespace) 사용으로 `data-hx-*` 패턴으로 호환성을 확보할 수도 있다.
실무적 관점: 저자의 Criticism은 스타일적 선택에 가깝지만, 대규모 팀에서는 웹 표준 준수 여부가 코드 리뷰 문화(Code Review Culture)와 직결되므로 무시하기 어려운 요소다.