Emotion 오버헤드 논란 종결? vanilla-extract 직접 비교 후기

2025-05-01

저희 회사는 사내 UI 라이브러리에 Emotion을 사용하고 있었는데, 최근에 이 Emotion을 제로 런타임 CSS-in-JS로 마이그레이션하면 어떠냐는 이야기가 나왔습니다.

프로덕트 특성상 성능이 사용자 경험에 직결되기 때문에 기존 Emotion에서 발생하는 런타임 오버헤드가 늘 신경 쓰였지만, 기술 스택을 바꾸는 것은 매우 조심스러울 수 밖에 없었습니다. 왜냐하면 현재 약 50개 가까이 되는 UI 컴포넌트를 모두 마이그레이션해야 하기 때문입니다. 비용적으로도 큰 문제가 될 것이고, 이 마이그레이션을 다른 업무와 병렬적으로 진행하는 것이 과연 가능할지도 문제가 됩니다. 이런 리스크에도 불구하고 마이그레이션을 통해 얻을 수 있는 이득이 명확하다면 진행하는게 맞겠죠.

그래서 직접 두 라이브러리의 성능 비교 테스트를 진행해서 직접 확인을 하기로 했습니다. 그리고 생각보다 흥미로운 결과가 나왔기에 공유하려고 합니다.

테스트 방식

실제로 사용하고 있는 컴포넌트를 vanilla-extract로 마이그레이션해서 성능이 얼마나 개선될지 확인하는 게 가장 정확하겠지만, 그러기엔 공수가 지나치게 많이 든다고 생각했습니다. 그래서 간단하게 vite + react + typescript 프로젝트 두 개를 만들어서 Button 컴포넌트를 개발했습니다. 한쪽은 Emotion으로, 다른 한쪽은 vanilla-extract로 스타일링한 다음, App.tsx에 이 Button 컴포넌트들을 1000개 렌더링해서 성능을 비교하는 테스트를 진행했습니다. 제가 성능 비교 테스트를 위해 만든 프로젝트는 아래 링크에서 확인할 수 있습니다.


Emotion

vanilla-extracrt

테스트 결과

React Profiler

우선 React Profiler로 확인해보니 아주 흥미로운 결과를 확인할 수 있었습니다.

React Profiler에서 'Render duration'은 React가 가상 DOM 트리를 구성하고 실제 DOM에 반영하는 데 소요되는 시간을 의미합니다. 이 지표를 통해 vanilla-extract가 Emotion보다 확실히 렌더링 성능이 우수하다는 것을 확인할 수 있었습니다. (206.8ms에서 98.4ms로 소요 시간 약 52.4%가량 감소)


Emotion

image

vanilla-extract

image

Vite size

다음으로는 번들 파일 크기를 비교하기 위해 vite-size 도구를 사용했습니다.

측정 결과, JS 파일 크기는 약 21.7KB 감소했으며, gzip 압축 시 사이즈는 약 8.1KB 감소한 것을 확인했습니다.

emotion

image

vanilla-extract

image
image


결론

직접 진행한 성능 비교 테스트 결과는 예상보다 훨씬 드라마틱했습니다. 특히 렌더링 속도와 번들 크기에서의 유의미한 개선은, 비록 초기 마이그레이션에 시간과 노력이 필요하더라도 장기적으로 더 나은 프로덕트와 사용자 경험을 위해서는 충분히 가치 있는 투자가 될 것이라는 확신을 주었습니다.

이 테스트 결과를 팀원들에게 공유했고 팀원들 역시 이 결과에 공감하며 Emotion에서 vanilla-extract로의 전환을 진행하기로 최종 결정했습니다!

이제 본격적으로 마이그레이션 여정이 시작될 텐데, 이 과정을 통해 저희 프로덕트가 얼마나 더 빠르고 효율적으로 변화할지 정말 기대됩니다. 이번 경험이 비슷한 상황에서 고민을 하고 계실지 모르는, 이 글을 읽는 분들에게도 좋은 참고가 되기를 바랍니다! 😊

© 2025 Kae All Rights Reserved.