Turbo Drive의 동작 방식과 문제점
Turbo Drive는 링크 클릭 및 폼 제출을 가로채어 전체 HTML을 AJAX로 가져온 후, <head> 내용은 유지하고 <body> 요소만 새로운 콘텐츠로 교체합니다. 이는 페이지 전환 속도를 크게 향상시키지만, <body>에 직접 코드를 삽입하는 서드파티 위젯에는 문제를 야기합니다. 위젯의 JavaScript는 초기 페이지 로드 시 채팅 창을 렌더링하고 관리하는 코드를 document.body에 삽입하지만, Turbo Drive가 페이지 이동 시 <body> 전체를 교체하면서 위젯도 함께 사라지게 됩니다.
data-turbo-permanent 시도와 한계
Rails는 이러한 상황을 위해 data-turbo-permanent 속성을 제공하여 특정 요소가 페이지 로드 간에도 유지되도록 합니다. 문서에 따르면 이는 해결책처럼 보였으나, 실제 적용에는 어려움이 있었습니다. 위젯 마크업이 페이지 렌더링 후 동적으로 로드되므로 직접 data-turbo-permanent를 추가하기 어려웠습니다. 이를 우회하기 위해 MutationObserver를 사용하여 위젯이 비동기적으로 추가되는 즉시 data-turbo-permanent를 가진 컨테이너 div로 이동시켰습니다. 그러나 위젯이 iframe으로 구현되어 있었기 때문에, 요소 자체는 유지되더라도 iframe은 모든 상태와 서드파티 원격 위젯 플랫폼과의 연결을 잃어버리는 문제가 발생했습니다. 결과적으로 채팅 버블의 흔적만 남고 실제 서비스 콘텐츠는 사라지는 현상이 나타났습니다.
‘Out of Body Experience’ 해결책
문제가 Turbo Drive의 <body> 교체와 iframe의 상태 유지 한계에 있음을 파악한 후, 위젯을 <body> 태그 외부로 완전히 이동시키는 아이디어를 시도했습니다. 이전과 동일하게 MutationObserver를 사용하여 위젯이 페이지에 추가되면 즉시 <body> 밖으로 이동시키는 방식을 적용했습니다. 놀랍게도 이 방법은 완벽하게 작동했습니다. 위젯 아이콘은 페이지 전환 간에도 지속되었고, 심지어 채팅 창을 열어둔 상태에서도 그 상태가 유지되었습니다. 비록 기술적으로 ‘합법적인’ HTML 마크업은 아니지만, 이 방법은 매우 효과적이었습니다.
DHH의 제안
Rails World 컨퍼런스에서 DHH는 turbo:before-render 이벤트를 가로채고, Turbo Drive가 <body> 내부의 특정 div만 교체하도록 하는 방안을 제안했습니다. 이 방식은 위젯을 해당 div 외부에 배치하여 교체되지 않도록 하는 것으로, 더 표준적인 해결책입니다. 하지만 이는 더 많은 코드를 필요로 하며, 저자는 비록 비표준일지라도 간단하고 효과적인 ‘Out of Body’ 해결책을 여전히 선호한다고 밝혔습니다.