es-toolkit, 사내 작은 라이브러리가 전세계적인 라이브러리가 되기까지
안녕하세요, 토스 Frontend Engineering Head 박서진, 토스뱅크 Frontend Developer 이다용입니다.
오늘은 토스의 작은 유틸리티 함수 라이브러리로 시작한 es-toolkit이 어떻게 일주일에 2천만 회 이상 다운로드되고, Yarn이나 Recharts 같은 핵심 라이브러리에서도 사용되었는지 그 성장한 과정을 소개해 드릴게요.
[서진] es-toolkit의 시작
프론트엔드 개발자로서 throttle, debounce 나 uniq 같은 함수들이 자주 필요해요. 그런데 지금까지는 자신 있게 이러한 유틸리티 함수들을 활용할 방법이 없었어요.
lodash 같은 유명한 라이브러리를 활용하는 방법도 있었지만, 기본적으로 lodash는 이렇게 낡은 코드 구조를 가지고 있고, Array#map 같이 이제 브라우저가 기본적으로 제공하는 함수가 아니라 모든 로직을 직접 구현하고 있었어요. 이외로 Internet Explorer를 위한 방어적인 로직같이 현대 웹 개발에는 필요하지 않은 로직이 불필요하게 들어가 있었어요.

ECMAScript Modules도 지원하지 않아서, 현대 웹 개발에서 일반화된 Tree-shaking을 통해 사용하는 로직만 포함하는 것도 어려웠어요.
lodash-es 같이 기존 lodash 코드에 ECMAScript Modules 지원만 추가한 라이브러리를 사용하는 것도 방법이었지만, 여전히 코드가 낡고 비효율적으로 동작한다는 사실은 변하지 않았어요.
이런 상황에서 lodash 를 대체할 만한 유틸리티 라이브러리를 아무리 찾아보아도 마땅한 라이브러리가 없었어요. 결국 토스팀에서도 @toss/utils 같은 토스 안에서의 공통 유틸리티 라이브러리를 만들어서 관리하기도 했죠. 그렇지만 공통 유틸리티 라이브러리에서 직접 모든 함수들을 구현하기에는 부담도 있었고, 생각보다 유틸리티 함수에는 엣지 케이스가 많아서 이를 꼼꼼히 대응하는 데에 시간을 썼어요.
현대 웹 개발 환경에 맞게 잘 만들어진 검증된 라이브러리가 필요하다고 생각했어요.
이 문제는 우리만 겪고 있는 문제는 아닐 것이라고 생각했어요. 실제로 주변에 다른 회사에 다니는 프론트엔드 개발자 분들은 울며 겨자 먹기로 lodash 또는 lodash-es 를 사용하거나, 자체적으로 유틸리티 라이브러리를 만들어 사용하지만 불편함을 느끼고 계시더라구요.
그래서 새로 @toss/utils 를 기반으로 현대적인 JavaScript 유틸리티 라이브러리를 만들어야 한다고 생각했고, es-toolkit 프로젝트를 시작하게 됐어요. 목표는 간단했어요. "lodash의 비효율적인 로직들을 걷어낸 효율적인 유틸리티 라이브러리를 만들어서 성능은 빠르게 하고, 불필요한 코드는 걷어내자."
실제로 lodash 에서 제공하는 핵심적인 함수들 위주로 구현을 해보니까 효과가 놀라웠어요. 함수에 따라서 달랐지만, 불필요한 로직를 제거하는 것만으로 최소 2배, 최대 10배 이상 속도가 빨라졌어요.

번들 사이즈의 변화는 더 드라마틱했어요. 오래된 브라우저를 지원하는 불필요한 코드를 제거하고, 현대 브라우저에서 이미 보편화된 Array#map 같은 함수를 직접 사용하도록 하니까 번들 사이즈가 30배 이상 줄어들기도 했어요.

이러한 모습을 보면서 es-toolkit 라이브러리의 혜택을 줄 수 있는 사람들이 적지 않을 것 같다고 생각했어요.
[서진] 한국과 해외에서 뜨거운 관심을 받다
es-toolkit의 첫 버전을 만들고 난 후, 첫 결과를 토스 프론트엔드 SNS에 공개했어요. 생각보다 더 큰 관심을 받았죠.

생각보다 많은 프론트엔드 개발자 분들께서 사용하기 시작했고, 기여도 간간히 올라왔어요. 빠진 함수를 구현해 주기도 하고, 버그를 수정해 주시기도 하고, 최적화가 덜 된 부분을 최적화 해주시기도 했죠.
한국에서의 관심을 바탕으로, 이러한 문제가 한국에서만 있지는 않을 것 같다고 생각했어요. 그래서 많은 해외 개발자 분들이 모이는 해외 개발자 사이트에 프로젝트를 알렸어요.

프로젝트를 알리니까 폭발적인 반응이 있었어요. 100개 이상의 추천을 받아서 수만 명의 분들이 오픈소스 레포지토리를 열람해 주셨고, 댓글에서도 "어떻게 한 거야?", "이렇게 하면 더 좋지 않을까?" 같은 논의가 한동안 지속되었어요.

해외 개발자 커뮤니티에서 논의가 뜨거워지니까, 유명 블로그나 유명 뉴스레터에서도 소식을 알리기 시작했어요. 그랬더니 더 많은 분들이 참여해 주시기 시작했죠.


커뮤니티에서 자발적으로 lodash를 es-toolkit으로 대체하는 번들러 플러그인을 만들거나, 유명 라이브러리의 의존성을 es-toolkit으로 바꿔 주시기도 하셨어요.

[다용] 처음에는 외부 오픈소스 기여자로 es-toolkit에 참여하다
es-toolkit 라이브러리를 알기 전부터, 저는 평소에 이런 의문이 있었어요. "왜 한국에서는 좋은 오픈소스 프로젝트가 많지 않을까?"
그러던 어느 날, 토스 프론트엔드 트위터에서 우연히 es-toolkit 라이브러리의 소식을 봤어요. 유명한 라이브러리였던 lodash보다 성능이 빠른 es-toolkit이 해외에서도 폭발적인 반응을 얻고 있다는 소식이었어요.

한국에서도 프론트엔드 생태계에 기여하는 큰 오픈소스 프로젝트가 나왔으면 한다는 마음이 들었어요. 게다가 평소 좋아하던 회사에서 운영한다고 하니, 더 기여하고 싶다는 생각이 들었어요. 오픈소스이다 보니까 토스 직원이 아니라고 하더라도 충분히 Pull Request를 올릴 수도 있었고요. 그래서 바로 레포지토리를 클론 받고 작은 이슈부터 조금씩 기여를 시작했어요.

작은 Pull Request였지만 조금씩 라이브러리가 발전하는 과정에서 기여하는 모습을 보니 뿌듯함이 있었어요. 그래서 하나씩 하나씩 꾸준히 기여를 했었죠.
그러다가 외부 기술 컨퍼런스에서 우연히 서진님을 직접 만나뵈었어요. 반갑게 인사해 주시고 저를 기억해 주시던 게 아직도 생각나요. 짧은 대화였지만, 서진님도 "한국에서도 프론트엔드 생태계에 기여하고 싶다"라는 같은 생각을 품고 있다는 걸 느낄 수 있었어요. 바쁜 일정 속에서도 OSS를 운영하시는 모습에 자극도 받았고요.
그때부터 더 열심히 기여했고, 그렇게 2위 기여자까지 됐어요.

es-toolkit 라이브러리에 Pull Request를 올리고 리뷰받는 과정에서 인터페이스 설계 원칙이나 JavaScript 언어에 대해서 많이 배울 수 있었어요. 그래서 그렇게 쌓인 경험이 토스뱅크 입사로 이어졌죠.
[다용] 실질적으로 프론트엔드 생태계에 기여하다
es-toolkit 라이브러리에 서진님, 저, 그리고 국내외의 많은 기여자 분들이 기여하기 시작하면서 점점 더 완성도를 높여가고 있었어요. 그런데 우리 라이브러리가 빠르게 완성되어가는 것과 달리, 생태계에서는 천천히 채택이 되고 있더라고요. 아직도 오래된 버전의 유틸리티 라이브러리를 사용하는 사람이 엄청 많았어요.
그래서 "어떻게 하면 더 빠르게 더 많은 사람들이 빠른 성능과 작은 번들 사이즈의 혜택을 누릴 수 있을까?" 라는 질문을 던졌어요.
이미 lodash 같은 유틸리티 라이브러리를 사용하고 있는 프로젝트들을 먼저 봤어요. 그런데 유틸리티 라이브러리의 특성 상 프로젝트 곳곳에서 많은 함수를 불러와서 사용하고 있더라고요. 이 많은 함수를 하나하나 바꾸면서 마이그레이션 하는 것에는 부담이 있을 것이라는 생각이 들었어요. 그래서 lodash의 drop-in replacement, 즉 import 문만 바꾸면 바로 혜택을 볼 수 있는 방법을 제공할 필요가 있다고 생각했어요.
es-toolkit은 메이저한 유스케이스에 집중했다 보니, 모든 경우의 수를 고려하는 lodash와는 동작이 다른 경우가 많았어요. 그래서 큰 고민을 하지 않고 바로 비슷한 함수로 바꾸면 런타임에서 오류가 발생하는 경우가 있었어요.
그래서 실제 인터페이스와 동작을 최대한 호환되게 맞추되, 내부 구현만을 현대화한 중간 레이어를 뒀어요. 일단 진입 장벽을 낮춰서 es-toolkit 사용자로 만드는 거예요. 그렇게 나온 게 es-toolkit/compat이에요. 내부 구현을 현대화하기만 해도 성능은 빨라지고 번들 사이즈는 작아졌어요.
이렇게 하니까 흐름이 달라졌어요. 서비스를 개발하는 회사들뿐만 아니라 Storybook, Mermaid, Yarn Berry 같은 큰 오픈소스 프로젝트들까지 es-toolkit을 채택하기 시작했거든요. 더 많은 사람들이 es-toolkit의 가치를 느끼고 전파해 주시기 시작했어요. 곧바로 NPM 다운로드도 기하급수적으로 늘었어요.

저도 es-toolkit의 가치를 느끼면서, es-toolkit을 더 많은 사람들이 사용하면 좋겠다는 생각에 한동안은 외부 라이브러리들에 적극적으로 기여하기 시작했어요. 직접 마이그레이션도 하고, es-toolkit이 제공하는 성능에 대해서 자세히 설명하기도 하면서 마치 영업하듯 여기저기 돌아다녔죠. 그 과정에서 더 많은 기여자 분들이 함께해 주셨고, 토스의 오픈소스 위원회 (지금의 Slash Team) 분들도 많은 도움을 주셨어요.
덕분에 지금은 recharts 같은 큰 오픈소스 프로젝트부터 작은 서비스들까지 다양한 곳에서 es-toolkit이 사용되고 있어요. NPM 주간 다운로드는 2천만 회를 넘겼죠.
[서진] 앞으로의 es-toolkit
지금까지 성장해 온 es-toolkit, 앞으로는 어떤 방향을 바라보고 있을까요?
먼저, es-toolkit은 지속적으로 프론트엔드와 JavaScript 생태계 전체가 더 좋은 선택을 내릴 수 있도록 기여하려고 해요. 지금까지 Yarn Berry, Recharts 등의 라이브러리가 es-toolkit을 활용하면서 최종적으로 번들 사이즈를 감축했던 것처럼, 더 많은 라이브러리들이 혜택을 누릴 수 있도록 하고 싶어요.
또한 오픈소스 생태계에서 필요한 새로운 함수들이 있으면, 그러한 니즈를 기민하게 캐치해서 기여하려고 해요. 예를 들어, Map 이나 Set 같은 내장 자료구조에서 filter 같은 함수를 구현하기 어려웠다거나 (#), Promise를 사용하는 중 자주 사용하는 delay 함수(#)처럼 최신 JavaScript 생태계에 맞는 유틸리티 함수를 추가로 제공하고 싶어요.
마지막으로, 모든 환경의 JavaScript 환경에서 사용되는 함수들뿐만 아니라, Node.js/Deno/Bun 환경처럼 서버에서 사용되는 각종 함수들도 제공하며 종합적인 유틸리티 라이브러리로 성장하려고 해요. es-toolkit의 정신인 "80% 이상의 유스케이스에 최적화해서 작고 빠르게 동작하게 한다" 를 유지하는 고품질의 함수들을 제공하고 있어요. 예를 들어, 최근 추가된 exec 함수 (#) 는 경쟁 JavaScript 함수들보다 훨씬 더 작은 구현체를 제공하면서도, 꼭 필요한 기능들은 모두 담고 있어요.
es-toolkit은 단순하지만 JavaScript 생태계에 어떤 라이브러리보다도 크게 기여하는 라이브러리가 되고 싶어요. 앞으로도 es-toolkit이 세계적인 라이브러리가 될 수 있도록 많은 응원과 기여 부탁드릴게요.
토스의 Slash Team은 es-toolkit처럼 프론트엔드 생태계에 도움이 될 수 있는 JavaScript/TypeScript 패키지를 만드는 팀이에요. es-toolkit부터 es-hangul, overlay-kit 같은 편리한 패키지를 만들어서 제공하고 있죠. 이렇게 프론트엔드 생태계에 기여하는 라이브러리를 함께 만들어 가보고 싶으신 분들은 여기에서 함께 만들어 가요!
