지난 10월 25일, Next.js 컨퍼런스가 개최되었습니다. Next.js
13 버전이 발표되면서 여러 새로운 기능들이 소개되었는데, 특히 새로운 번들러로 Turbopack이라는 도구가 함께 소개되면서 화제가 되었습니다.
개인적으로는 회사에서 Vue 3
+ Nuxt 3
프로젝트를 진행하면서 Vite
를 함께 접해보았기 때문인지, 가장 먼저 번들러인 Turbopack
에 먼저 눈길이 가기도 했습니다.
개발사인 Vercel의 소개에 따르면, Turbopack
은 Rust
로 개발된 번들러인 Turbo를 기반으로 하는 차세대 자바스크립트 모듈 번들러입니다. webpack
의 후속이자, 창시자인 Tobias Koppers가 리드하는 프로젝트이기도 합니다.
JavaScript로 개발되어 성능상 한계를 지니고 있던 전작에 비해, Rust로 개발된 만큼 극적인 성능 향상(특히 애플리케이션의 규모가 클 수록)이 있으며, 이는 '동일한 작업을 두 번 수행하지 않는' - 캐싱과 메모이제이션을 활용한 아키텍처 덕분이라고 말하고 있습니다. 공식적으로는 아래와 같이 제시하고 있는데, Next.js blog의 아티클을 인용해 보겠습니다.
webpack
대비 700배 빠른 업데이트 속도webpack
대비 4배 빠른 콜드 스타트(초기 실행 속도)Vite
대비 10배 빠른 업데이트 속도
트랜스파일러인 Babel
, 맹글러인 terser
를 마이그레이션하고 개발에 필요한 최소한의 리소스만 번들링하는 등의 방법으로 속도를 개선했다고 하는데, 여기서 webpack
과 Vite
를 대조군으로 두고 있는 점을 주목할 만합니다.
웹 프론트엔드 생태계에서 webpack
은 다루지 않고 넘어갈 수 없는 도구이고, 지금까지 30억 회 이상 다운로드되었을 만큼 막강한 위상을 차지하고 있지만, 항상 두 가지 한계점이 꾸준하게 지적되어 왔습니다. 첫째는 너무 느리다는 것, 둘째는 설정이 복잡하고 어렵다는 것입니다.
갈수록 난잡하고 비대해져만 가는 프론트엔드 개발 환경으로 인해, 개발자 경험이 저해되는 문제 등으로 비판과 자성의 목소리까지 나오고 있는 상황임을 생각해보면 두 번째 문제 - '복잡하고 어렵다'는 꽤나 중대한 결점입니다.
하지만 성숙한 생태계 덕에 베스트 프랙티스도 많고, 특히 CRA
같은 스캐폴딩 도구라던가 Next
나 Nuxt
와 같은 프레임워크의 도움을 받는 경우에는 그렇게까지 깊게는 신경쓰지 않을 수 있기도 해서, 막상 실제로는 별로 체감이 되지 않는 문제일 수도 있습니다.
그래서 보다 핵심적인 문제는 첫 번째라고 할 수 있습니다. 성능은 당장 생산성에 중대한 영향을 미칠 뿐더러, 개발자가 다른 것이면 모를까 느린 것을 참을 수 있을 리 없을 것이기 때문입니다.
실제로 조금만 구글링을 해 보아도 webpack
의 빌드가 느리다는 이슈는 아주 흔히 찾아볼 수 있고, 수많은 기술 블로그들의 아티클에서는 어떻게 하면 빌드 퍼포먼스를 개선할 수 있을지를 토픽으로 다루고 있을 정도입니다. 특히 최근 1~2년 사이에는 퍼포먼스 문제로 기존 프로젝트에서 webpack
을 Vite
로 마이그레이션했다는 사례도 꽤 자주 보이고 있기도 합니다.
JavaScript 개발자들을 대상으로 한 설문조사 결과인 State of JS 2022에서도,
webpack
의 사용량은 조금씩 감소하고 있는 반면Vite
의 사용량은 급격히 증가하고 있는 추세가 나타납니다.
관점에 따라 다를 수는 있지만, 어떤 문제를 해결하고자 도입한 도구가 새로운 문제들을 만들어낸다면 그것은 일종의 주객전도일 수 있는데, webpack
이 바로 그러한 사례라고 할 수 있는 셈입니다.
그래서인지 그동안 다른 여러 번들러들이 webpack
대비 빠르거나 쉬움을 강점으로 내세우며 도전장을 내밀기도 했습니다. 하지만 결국 하나의 대안이 되었을 뿐 탄탄한 생태계를 갖추거나 완전한 '대세'가 되진 못했습니다.
그러다 Vue
의 개발자인 Evan You가 Vite
를 내놓게 되면서, 드디어 webpack
의 유력한 경쟁자로 떠오르게 됩니다.
Vite
('비트/vit/' 라고 읽습니다)는 그동안 제안된 다른 좋은 아이디어나 도구들을 재조합/통합하고, 부족했던 부분을 보완하거나 사용하기 더 편하게 개선하는 방식으로 개발되었다는 점이 두드러지는 모듈 번들러(공식 문서를 인용하자면 '웹 개발의 메타 프레임워크')입니다.
Vite
에 대해 이야기하려면 2020년 경 등장했던 Snowpack
에 대해 먼저 살펴볼 필요가 있는데, 이는 Vite가 기본적으로 Snowpack
이 제시했던 패러다임과 접근 방식을 따르고 있기 때문입니다.
기존의 번들러들이 가지고 있던 문제는, 모든 소스 코드와 모듈들을 포함한 코드 베이스 전체를 하나로 번들링하고, 일련의 빌드 프로세스를 거친 다음 번들된 코드를 브라우저에 제공하는 작업 자체가 너무 무겁고 비효율적이었다는 것이었습니다.
코드가 업데이트되면 전체 파이프라인을 처음부터 다시 거쳐야 했으므로, 코드 베이스의 규모가 커질 수록 업데이트 시간도 선형적으로 증가했습니다.
그래서 Snowpack
은 '필요해서가 아니라 원하기 때문에 번들러를 사용할 수 있어야 한다'는 철학으로, (개발 환경에서는) 번들링을 하지 않기로 합니다. 이것이 가능해진 배경으로 브라우저에서 네이티브 모듈(ECMAScript Module, ESM)을 사용할 수 있게 되었다는 점이 있긴 하지만, 어쨌든 그런 덕분에 프로덕션 빌드에서는 기존과 같이 webpack
을 사용해 완성된 코드 베이스를 만들되, 빠른 수정이 중요한 개발 환경에서는 번들링을 배제하고 모듈 각각을 별도로 빌드해서 수정이 발생한 파일만 업데이트하는 방식(Hot Module Replace, HMR)으로 퍼포먼스 문제를 해결하고자 했습니다.
특히 esbuild
라는 도구의 도움이 결정적이었는데, Go
기반으로 개발되어 webpack
에 대비해 빌드 속도가 최대 100배 가량 빨랐기 때문에 괄목할만한 개선이 가능했습니다. 다만 esbuild
는 어디까지나 빌드만 할 수 있는 도구였으므로, 이외의 여러 기능들(트랜스파일링, 코드 스플리팅, 트리 쉐이킹, HMR 등…)을 종합적으로 제공해줄 수 있는 webpack
같은 도구는 여전히 필요했습니다.
그러나 webpack
과의 연동 과정에서 버그나 호환성 문제가 발생하는 등 다소의 불안정성을 드러냈는데, 바로 이 지점에서 Vite
가 Snowpack
을 일종의 계승/흡수하는 형태로 이어나가게 되면서 Snowpack
은 개발이 중단되고 Vite
생태계로 편입됩니다. 특히 Vite
는 그동안 제시된 다른 대안이었던 Rollup
, Parcel
과 같은 도구들까지 통합한 형태였기 때문에, webpack
의 새로운 대안이 될 수 있었습니다.
구체적으로는 Snowpack
과 동일하게 빌드 도구로 esbuild
를 채택했으며, 프로덕션 빌드에는 Rollup
을 사용하여 webpack
처럼 통합적인 기능을 제공합니다. HMR은 ESM으로 HTTP 캐싱을 활용해 구현하므로 업데이트 속도가 매우 빠릅니다. 또한 기본적으로 최적화된, 단순한 설정이 제공되기 때문에 러닝 커브에 대한 부담이 상대적으로 적기도 합니다.
구체적으로 어떠한 기능들이 제공되는지는 공식 문서에서 가이드하고 있습니다.
Vue
의 개발자가 만들었고, 기본적으로 Vue를 위해 개발되었기 때문인지 Vue 진영에서만 사용할 수 있다는 인식이 있지만, React
나 Svelte
등에서도 범용적으로 사용할 수 있습니다.
특히 Svelte
의 경우 처음에는 Snowpack
을 채택했다가, Rollup
을 거쳐 최종적으로는 Vite
를 공식적으로 통합하기도 했습니다. (Rollup은 Svelte의 개발자인 Rich Harris가 직접 개발한 도구인 데다, 그가 현재 Vercel에서 근무하고 있다는 점을 생각해보면 재미있는 부분입니다)
이런 상황에서, Vercel에서 Turbopack
을 내놓았다는 것은 일종의 경쟁적인 구도로 보일 수 있는 대목이기도 합니다. 그렇지 않아도 프론트엔드 생태계에서 Vercel의 비중이나 영향력이 크기도 하거니와, 직접적으로 Vite
와 비교한 벤치마크 결과를 마케팅하고 있다는 점에서 특히 그렇습니다.
물론, 경쟁과 수렴 진화를 통해 웹 생태계와 기술이 진보할 수 있다면야 바람직한 일이고, 그걸 가져다 활용하는 개발자들의 입장에서는 어쨌든 감사하고 좋은 일인 것은 분명합니다.
그런데 지난 10월 29일, Vite
의 개발자 Evan You가 Turbopack
의 벤치마크 데이터를 보고 아래와 같은 의문을 제기합니다.
Vercel에서는 Vite
대비 10배, 상황에 따라 크게는 20배까지 업데이트 속도(HMR)가 빠르다고 주장하며 벤치마크 데이터를 제시하기는 했지만, Evan 본인이 직접 벤치마크를 수행해보니 전혀 그 정도로는 차이가 나지 않았고, 애초에 방법론이 잘못되어 불공정한 비교가 되었다는 것입니다. 공개 검증이 가능하도록 직접 코드를 올리기도 했는데 - Vite vs. Next + Turbopack HMR Benchmark - 벤치마크 데이터의 일부를 인용해보면 아래와 같습니다.
Vite (root) | Vite (leaf) | Next (Client / root) | Next (Client / leaf) | Next (RSC / root) | Next (RSC / leaf) | |
---|---|---|---|---|---|---|
1 | 342 | 141 | 335 | 87 | 782 | 661 |
2 | 358 | 141 | 343 | 72 | 912 | 633 |
3 | 352 | 143 | 334 | 88 | 922 | 453 |
4 | 337 | 139 | 337 | 85 | 829 | 640 |
5 | 302 | 145 | 324 | 90 | 737 | 539 |
평균 | 338.2 | 141.8 | 334.6 | 84.4 | 836.4 | 585.2 |
(여기서 root는 import와 자식 컴포넌트가 많은 부모 컴포넌트를, leaf는 import가 없는 작은 자식 컴포넌트를 의미하며, RSC는 React Server Components를 말합니다.)
leaf 컴포넌트에서는 Turbopack
이 약 68% 빠르긴 하지만, root 컴포넌트라면 거의 비슷한 수준입니다. 즉 Vercel이 주장하는 10배는 잘못되었고, 최대 약 2배 정도라고 봐야 한다는 것입니다.
Evan은 구체적으로 벤치마크가 아래와 같은 부분에서 잘못되었다고 부연하고 있습니다.
- 트랜스파일러가 다름 :
Vite
의 경우 Babel 기반의 React 플러그인을 사용하고 있는 반면, Turbopack과 webpack은 모두SWC
를 사용하고 있으므로 불공정함- 어림이 잘못됨 : 1k 개의 컴포넌트를 벤치마크하는 케이스에서,
Turbopack
의 경우 15ms를 0.01초로 내림한 반면Vite
는 87ms를 0.09초로 반올림함. 이렇게 되면 실제로는 6배 차이임에도, 마케팅에서는 9배가 됨- 타임스탬프 측정 방법이 잘못됨 : 모듈이 업데이트 될 때 브라우저의 eval time을 타임스탬프로 측정했는데, 이는 이론적인 수치고 실제 사용자가 인식하는 end-to-end HMR 속도는 컴포넌트가 리렌더링된 시간으로 측정해야 함. 게다가 Vite는 타임스탬프 측정 방법에서도 결함이 있었음
- 그래프가 잘못됨 : 시작 속도를 비교하는 그래프에서, 모듈 수가 30k를 넘어서야
Turbopack
이Vite
보다 10배 정도 더 빠르다고 볼 수 있는데, 이런 케이스는 현실성도 없는 데다 10k 수준까지는 양쪽 모두 속도가 지속적/선형적으로 증가했음. 이론적으로나 가능한 케이스를 가져와 10배를 주장하는 건 '체리피킹'임
결국 Vercel의 주장은 다소 마케팅적인 과장이나 왜곡이 의도되었다고 볼 수 있는 셈이라고 할 수 있겠으며, 이에 Evan은 공정성과 상호 존중이 바탕된 오픈 소스 소프트웨어 생태계의 경쟁을 바란다는 취지의 코멘트를 남긴 상황입니다.
이번 이슈를 통해, 개발자에게 있어 어떤 기술과 도구의 가치를 스스로 판단할 수 있는 능력이 중요하다는 사실을 생각해볼 수 있었습니다. 현실적으로는 도구의 사용법을 배우는 일조차 벅차다 보니, 만약 어떤 기술을 검증하고 증명하기 위해 논리정연한 방법론을 설계해내고 실제 코드로 보여주어야 한다고 하면 과연 가능했을까 싶어 반성하게 됩니다.
그냥 누가 좋다고 하니까, 많이들 쓰는 트렌디한 기술이라고 하니까 별 생각 없이 무비판적으로 채택하고 사용하는 것은 엔지니어로서 부끄러운 일일 것입니다.
흔한 말이지만 개발자는 문제를 해결하는 사람이고, 문제를 잘 해결하기 위해서는 시의적절하게 최선의 수단을 선택할 수 있는 능력을 갖추어야 할 것이므로, 항상 기술에 대한 의심과 고민이 필요하다고 할 수 있겠습니다.
기술이 어려워야 유입되는 개발자도 적고 월급 많이 주는데 아깝네요.
쏟아지는 신기술들 검토해서 최선의 선택으로 하나를 골라 문서보며 공부해서 신규 프로젝트에 적용하고 각종 삽질 문제들 잡을때 쯤 새 기술 또 나옴. 거기에 RND 를 이해하고 받쳐 줄만한 회사도 드물어서 꾸역꾸역 욕먹으며 잘해보겠다고 인생을 갈아넣으며 붙여 놨는데 얼마전에 더 좋은거 나왔는데 머했냐고 욕먹음. 그래도 본인 스스로 뭔가를 이루었구나 만족하는 와중에 운영 이슈들 올라오는데 안되는거 계속 나옴. 구글링해도 레퍼런스 없음. 아~ 주옥같아도 남이 많이 쓰는데는 이유가 있구나 깨닿고 안 나뎀. 재미지고 행복한 것들은 회사 밖에 있구나~