- HTMX는 서버 렌더링 HTML을 중심으로 프런트엔드를 점진적으로 향상하며, React식 현대 JavaScript UI가 비대해지기 전의 방식에서 발전한 접근
- 자체 호스팅 podcast web app의 서버 리팩터링에서 SvelteKit을 DinoSsr로 교체하자 페이지 이동이 오디오 재생을 끊는 문제가 생겼고, HTMX로 <main> 영역만 갱신해 오디오 컴포넌트를 유지할 수 있었음
- HTMX는 프런트엔드 라이브러리로 배포되지만 구현의 상당 부분이 백엔드 템플릿과 서버 설정에 놓이며, HTML을 반환하는 HTTP 요청이 사실상 HTMX API 역할
- hx-* 속성, 클릭 가능한 <div> 예시, 인라인 JavaScript가 많은 고급 예시는 선언적 속성 템플릿의 한계와 문서상의 불만점
- 직접 만든 미니 구현은 304 캐싱, History API, <title> 교체, 포인터 이벤트 기반 프리로드를 주요 요소로 사용했고, 브라우저 JavaScript를 줄여 코드베이스를 더 작고 단순하게 만든 결과
HTMX의 위치
- HTMX는 현대 JavaScript UI를 거부하고 서버 렌더링 HTML을 선호하며, React로 프런트엔드가 비대해지기 전의 방식에서 발전한 접근
- 무한 스크롤과 실시간 검색 결과는 인기 있는 HTMX 예시이며, HTMX는 React 등이 풀려는 모든 문제를 해결하지 않고 제한적으로 보이지만 그 제한 안에서는 가치가 큰 도구
- HTMX는 “magic bullet”이 아니며, HTMX 뒤의 일부 아이디어가 HTMX 자체보다 더 중요하다는 관점이 핵심
실험
- 문서 읽기만으로는 충분하지 않아 실제 사용을 테스트했고, 자체 호스팅 podcast web app 서버 리팩터링이 HTMX 적용 대상
- 이전 구현은 SvelteKit 사용이었고, SvelteKit은 선호하는 도구지만 작은 웹사이트에는 부담스러울 수 있는 프레임워크
- 교체 대상은 직접 만들던 DinoSsr였으며, 같은 프로젝트는 정적 사이트 빌드와 북마크 블로그 제공에도 사용
- DinoSsr는 주로 서버 사이드 기반이며 프런트엔드 “islands”로 컴포넌트를 제공할 수 있지만, 전체 페이지 상호작용은 제공하지 않는 구조
- 오디오 플레이어 컴포넌트는 페이지 이동 중에도 유지되어야 하며, 페이지 이동이 전체 페이지를 다시 로드하면 재생 경험이 빠르게 종료되는 문제
- SvelteKit은 UI 업데이트와 프런트엔드 라우팅을 처리했지만, 새 빌드에서는 오디오 플레이어 컴포넌트만 프런트엔드 JavaScript를 사용하고 DinoSsr는 클라이언트 사이드 라우팅을 의도적으로 시도하지 않는 구조
- 페이지 몇 개는 <main> 섹션만 다르므로, HTMX로 링크를 점진적으로 향상하고 이 영역만 갱신하면 페이지 전체를 다시 로드하지 않고 오디오 컴포넌트를 유지 가능
- HTMX 적용은 잘 작동했지만, 곧 HTMX를 제거하고 같은 아이디어로 직접 만든 미니 버전으로 전환
HTMX에 대한 몇 가지 생각
- 이 실험에서 HTMX는 프런트엔드 Svelte의 대체재였지만, React처럼 바로 끼워 넣는 대체재가 아니라 사고방식의 큰 전환
- HTMX는 프런트엔드를 점진적으로 향상하는 JavaScript 라이브러리로 배포되지만, 구현의 대부분은 백엔드에서 이뤄지며 서버 템플릿과 설정은 직접 준비해야 하는 구조
- HTML을 제공하는 HTTP 요청은 사실상 HTMX API 역할이며, 올바른 캐싱을 위해 HTTP 헤더를 설정하는 세부 사항이 중요함
- 표준 data-* 속성과 dataset이 있는데 비표준 hx-* 접두 속성을 쓰는 점은 작은 불만
- HTMX 문서에는 <div> 예시가 많으며, 아래 예시는 사용자가 div를 클릭하면 /messages로 PUT 요청을 보내고 응답을 해당 div에 로드하는 구조
<div hx-put="/messages">
Put To Messages
</div>
- 사용자가 <div> 요소를 클릭해야 하는 예시는 바람직하지 않다는 비판
- 인라인 JavaScript를 사용하는 일부 고급 HTMX 예시는 다소 지저분해지며, 선언적 속성 템플릿의 한계를 보여주는 사례
- 비판과 별개로 HTMX는 제한적이지만 유용한 기능 집합을 제공하며, 많은 일반적인 웹 디자인 패턴을 향상할 수 있는 도구
직접 만들기
- HTMX를 성공적으로 추가한 직후 제거했고, 같은 아이디어를 사용해 직접 만든 미니 버전 구현
- 캐싱되는 fetch 요청을 허용하기 위해 last-modified, if-modified-since HTTP 헤더와 304 응답을 사용
- 기본 히스토리 통합에는 pushState와 popstate를 사용
- <title> 요소를 추출하고 교체하는 코드를 추가했으며, HTMX preload extension에서 영감을 받아 포인터 이벤트 기반 프리로드를 내장
- 포인터 이벤트 기반 프리로드는 click 이벤트가 발생하기 전에 fetch 요청을 시작해 작은 성능 향상을 제공
- 실험용 소스 코드는 매우 기본적이지만, 브라우저에 실제로 필요한 JavaScript가 적다는 점을 보여주는 구현
- HTMX 또는 “we have HTMX at home” 방식으로 코드베이스가 훨씬 작고 단순해진 결과
프런트엔드 JavaScript
- 템플릿과 컴포넌트는 아주 작은 웹사이트가 아니라면 코드 구성과 재사용에 사실상 필요하며, PHP, Ruby, Go, JavaScript 등으로 서버 사이드에서도 구현 가능
- 이런 구조를 브라우저에 복제하거나 브라우저에서만 구현할 필요는 없으며, React 등의 인기로 많은 개발자가 이 질문을 멈춘 상태
- 프런트엔드 JavaScript 피로는 실제이며, 오래된 서버 템플릿을 선호하면서도 JS UI를 과도하게 설계해 온 경험과 맞물리는 문제
- HTMX 자체가 아주 훌륭하지 않다고 보더라도, 그 철학은 현대 JavaScript 개발자를 부끄럽게 만들 만큼 강한 가치가 있는 접근