인터랙션 패키지 현대화
인터랙션 패키지: Emotion 의존성 제거와 inline style 전환
TL;DR
인터랙션 패키지는 모든 토스 서비스가 함께 쓰는 공용 패키지였어요. 서비스 쪽에서는 더 이상 Emotion을 직접 쓰지 않는 방향으로 정리되고 있었지만, 인터랙션 패키지 내부 구현은 여전히 Emotion에 의존하고 있었어요.
이 의존성은 패키지 안에만 머물지 않았어요. Emotion이 peerDependencies로 노출되어 있었기 때문에, 이 패키지를 쓰는 서비스들도 Emotion을 완전히 떼어내기 어려웠어요.
그래서 패키지의 styling runtime 의존성을 정리하기 위해 Emotion을 제거하고 React inline style 기반 구조로 전환했어요. 외부 styling library를 새로 들이는 대신, 공용 패키지의 의존성 계약을 더 단순하게 만드는 쪽을 선택했어요.
문제 정의 Problem
인터랙션 패키지는 공용 패키지라 내부 구현 선택이 소비 서비스의 의존성에까지 영향을 줬어요. 특히 peer dependency는 내부에서만 쓰는 기술이 아니라, 쓰는 쪽이 함께 만족해야 하는 계약에 가까웠어요.
서비스 쪽은 이미 Emotion을 더 안 쓰는 방향으로 정리되던 중이었어요. 하지만 인터랙션 패키지가 Emotion을 peer dependency로 요구하는 한, 소비 서비스는 Emotion을 완전히 제거하기 어려웠어요.
단순히 스타일 코드를 다른 문법으로 바꾸는 일은 아니었어요. 공용 패키지가 소비 서비스에 어떤 styling runtime을 요구할 것인지, 그리고 그 요구를 계속 유지할 만큼의 이유가 있는지 다시 판단해야 했어요.
접근 방식 Approach
외부 styling library 의존성을 새로 만들지 않는 쪽으로 접근했어요. Emotion을 다른 라이브러리로 단순히 바꾸는 대신, 공용 패키지에 새로운 styling toolchain 의존성을 추가하는 게 맞는지 먼저 봤어요.
처음에는 vanilla-extract도 살펴봤어요. 하지만 우리 배포 구조에서는 소비 서비스나 TDS 쪽 빌드 설정, 버전 호환성까지 같이 고려해야 했어요. zero-runtime library라고 해도 toolchain 의존성이 생긴다면, 공용 패키지의 계약을 단순하게 만드는 목표와 완전히 맞는 선택은 아닐 수 있었어요.
Emotion으로 작성된 스타일 중 selector나 pseudo state 의존이 강한 부분이 많지 않은지 확인했어요. 인터랙션 패키지 특성상 복잡한 CSS 문법을 많이 쓰지 않았기 때문에, 대부분의 스타일을 React inline style로 옮길 수 있다고 판단했어요.
Emotion 기반 구현과 package.json의 peerDependencies 항목을 함께 제거했어요. TDS 레거시 대응 코드는 TDS 담당 팀과 논의해 새 major 버전부터는 지원하지 않기로 정리했어요. Storybook에서 여러 인터랙션 컴포넌트 케이스를 확인한 뒤 major 업데이트로 릴리즈했고, 하위 호환 변경 사항은 마이그레이션 문서에 적어 뒀어요.
핵심 결정 Decision
vanilla-extract 대신 inline style로 바꿨어요.
Emotion을 제거한 목적은 공용 패키지의 의존성 경계를 단순하게 만드는 데 있었어요. 그래서 다른 styling library로 갈아타는 것만으로는 문제를 충분히 풀었다고 보기 어려웠어요.
물론 inline style에는 한계가 있어요. selector, pseudo state, media query처럼 CSS가 자연스럽게 다루는 표현을 직접 다루기 까다로워요. 다만 인터랙션 패키지에서는 그런 문법을 많이 쓰지 않았고, 패키지를 더 독립적으로 유지한다는 장점이 더 컸어요.
TDS 레거시 대응 코드를 계속 끌고 가면 Emotion 제거가 어려웠고 목표와도 맞지 않았어요. 그래서 새 major 버전에서 하위 호환을 일부 포기하는 변경으로 정리했어요.
해결 결과 Result
인터랙션 패키지 안에서 Emotion 기반 스타일 구현을 걷어냈고, peerDependencies에서도 Emotion을 제거했어요.
인터랙션 패키지를 의존하던 서비스나 다른 패키지에서도 Emotion을 떼어낼 수 있는 상태가 됐어요. 스타일링 방식이 특정 runtime library에 묶이지 않게 되면서, 인터랙션 패키지를 더 독립적인 공용 패키지로 끌고 갈 여지가 생겼어요.
배운 점 Learning
이 작업을 하면서 공용 패키지의 의존성은 단순한 구현 선택이 아니라, 그 패키지를 쓰는 서비스로 번지는 계약이라는 걸 다시 느꼈어요.
특히 peerDependencies는 내부에서만 쓰는 기술이 아니라 쓰는 쪽에도 영향을 주는 결정이라 더 조심해서 골라야 해요. zero-runtime library라고 해서 늘 공용 패키지에 맞는 선택은 아니라는 것도 배웠어요. 런타임 비용이 없더라도 빌드 설정, 버전 호환성, toolchain 의존성이 따라붙는다면, 패키지의 역할에 따라 더 단순한 inline style이 나은 선택일 수 있었어요.