자바스크립트 프레임워크 비교

애플리케이션 파일 크기 중심으로

웹 프론트엔드 쪽에서는 애플리케이션의 파일 크기가 작을수록 성능 면에서 유리하다는 인식이 있다. 실제로 성능을 측정할 때 애플리케이션 파일의 다운로드 속도가 중요한 지표로 사용되니까 어느 정도는 맞는 말이기도 하다. 그래서 Solid 같은 프레임워크는 파일의 크기가 아주 작다는 것을 강조하기도 한다.

출처: SolidJS 공식 사이트

그러다 해외 사이트에서 각 프레임워크로 TodoMVC 애플리케이션을 작성하면서 파일 크기를 비교한 글을 보게 되었다 원본이 된 글은 JavaScript Framework TodoMVC Size Comparison으로 작년 10월에 작성된 글이다. 시간이 조금 흐르긴 했지만, 비교 대상으로 사용된 프레임워크가 2022년 6월 현재도 왕성하게 사용되고 있으며, 그사이에 큰 변화가 있었던 것은 아니라서 아마 다시 작성해도 결과가 비슷할 것이라 예상했다. 그래서 그냥 해당 글을 소개하는 선에서 이 글을 마치려고 했는데... 이왕 글을 작성하는 김에 조금 더 고생을 추가해서 2022년 6월 버전의 데이터를 만들어보고 싶었다.

각 프레임워크로 구현된 TodoMVC는 원본 글을 작성한 Ryan Carniato의 것을 기반으로 했다. 현재 버전에서 조금씩 안 맞는 부분이 있으며, 특히 React에서는 Warning 메시지도 많이 나타나고 className이 아니라 class 속성을 사용하는 등 React에 맞지 않는 여러 오류가 있어서 일부는 직접 수정했다. 참고로 Ryan은 Solid 프레임워크의 개발자이다. 원본 글에는 코드를 작성할 때 최대한 공평하게 하려고 노력했지만, 자신도 모르게 편파적인 부분이 있을 수도 있다며 참고하라고 쓰여 있다.

테스트 방법

테스트 방법은 원본 글의 방법을 따랐다. TodoMVC를 여러 프레임워크로 작성한 후 애플리케이션의 크기를 비교한다. 초기 로딩 속도라거나 반응 속도 등은 테스트 대상이 아니므로 프레임워크 비교 자료로는 다소 부족할 수도 있다. 그렇지만 앞서 말했듯이 파일의 크기도 성능을 측정하는 요소 중 하나이므로 참고 정도는 될 것이다.

사실 이 같은 테스트 방법은 Vue의 개발자인 Evan You가 Svelte와 Vue 컴포넌트의 코드 크기 비교라는 글에서 먼저 사용했다. Ryan은 그 글에 영감을 받아 Preact, React, Solid도 추가해서 같은 방식으로 비교했고, 그 Ryan의 글에 영감을 받은 내가 같은 방법으로 프레임워크의 버전만 업데이트해서(+코드 오류 수정) 다시 테스트한 것이다. 다만 Ryan은 TodoMVC의 코드만 공개했을 뿐 테스트 코드를 공개한 건 아니라서 Evan You의 코드를 바탕으로 내가 직접 벤치마크 코드를 작성했고, 해당 코드는 GitHub 저장소에 공개해두었다. 혹시 오류 또는 편파성을 발견한다면 이 글의 댓글 혹은 해당 저장소의 이슈를 통해 알려주면 좋겠다.

각 애플리케이션은 Vite로 번들링 한 후, gzip과 brotli 방식으로 압축했다. 테스트에 사용된 각 프레임워크의 버전은 다음과 같다.

  • React v18.1.0
  • Preact v10.7.3
  • Solid v1.4.4
  • Svelte v3.48.0
  • Vue v3.2.37

또한 프레임워크의 크기와 컴포넌트의 크기를 별도로 측정했는데, 컴포넌트의 크기만 구해서 애플리케이션이 복잡해졌을 때의 크기를 대략 추정하고 싶었기 때문이다. 원본 글과 같은 방식이다. 이는 결과 항목에서 조금 더 자세히 다루겠다.

결과

프레임워크별로 측정한 애플리케이션의 크기는 다음과 같다. Vendor 항목이 프레임워크 자체의 크기이고 Component 항목이 프레임워크를 제외한 애플리케이션의 크기가 된다. 여기에서는 실제 프로덕션 환경에서 사용될 크기에 가까운 압축 결과 중에 단순함을 위해 Brotli로 압축한 버전만을 비교하도록 하겠다. gzip 압축 결과와 brotli 압축 결과가 거의 비례하므로 굳이 gzip 버전은 싣지 않아도 될 것이다.

PreactReactSolidSvelteVue
Component (brotli)1.57 kB1.63 kB1.67 kB2.34 kB1.5 kB
Vendor (brotli)4.61 kB39.6 kB4.68 kB1.58 kB20.2 kB

8개월 전에 비해 Preact의 벤더 파일 크기는 거의 변하지 않은 반면, Solid의 벤더 파일 크기는 다소 증가했음을 알 수 있다. 흥미로운 점은 Svelte의 벤더 파일 크기는 오히려 감소했다는 것이다(1.85 kB ➝ 1.58 kB). 대체로 프레임워크의 버전이 증가하면 기능도 늘어나서 파일 크기가 증가하는 게 일반적인데 Svelte는 벤더 파일의 크기가 감소했다. 다만, 원본 글에서 측정한 방식과 이 글의 측정 방식에 차이가 있을 수 있다는 점은 감안해야 한다. 앞서 말했듯이 벤치마크 코드는 공개되지 않아서 내가 직접 작성해야 했기 때문이다.

어떤 애플리케이션이 있는데 TodoMVC 같은 컴포넌트가 몇 배는 더 많이 필요하다고 가정해보자. 예를 들어, 10배쯤 큰 애플리케이션이라면 벤더 파일은 한 번만 읽어 들이면 되기 때문에 해당 애플리케이션의 크기는 (컴포넌트 파일 크기 x 10) + 벤더 파일 크기로 예상할 수 있다. 같은 방식으로 컴포넌트의 개수에 따른 전체 애플리케이션의 크기를 구한다면 다음과 같을 것이다.

1510204080
Preact6.18 kB12.46 kB20.31 kB36.01 kB67.41 kB130.21 kB
React41.23 kB47.75 kB55.9 kB72.2 kB104.8 kB170 kB
Solid6.35 kB13.03 kB21.38 kB38.08 kB71.48 kB138.28 kB
Svelte3.92 kB13.28 kB24.98 kB48.38 kB95.18 kB188.78 kB
Vue21.7 kB27.7 kB35.2 kB50.2 kB80.2 kB140.2 kB

시간이 지나서든, 혹은 벤치마크 방법에 차이가 있어서든 자세한 숫자는 원본 글과 다르지만 결과의 방향성은 대체로 비슷하다. Svelte는 컴포넌트 개수가 늘어날수록 애플리케이션의 크기가 다른 프레임워크에 비해 빠르게 증가한다. TodoMVC의 80배쯤 되었을 때는 프레임워크 중 가장 파일 크기가 큰 React 보다 더 커진다. 그래프로 표시해보면 더 명확하게 도드라지는 Svelte의 증가 기울기를 볼 수 있다.

노파심에서 말하지만, 이 결과는 어디까지나 굉장히 단순한 방법으로 도출한 추정치일 뿐 실사용 환경과는 차이가 있을 수 있으며 프레임워크의 우열을 의미하는 지표도 아니다. 또한 이러한 추정 방식은 Evan You와 Ryan이 사용한 방법을 그대로 따른 것임을 다시 한번 밝힌다.

분석 및 결론

자, 각 프레임워크로 만든 애플리케이션의 파일 크기는 구했다. 그래서?

위 자료에서 확인하다시피 애플리케이션의 크기에 따라 용량 면에서 더 효율적인 프레임워크가 존재한다고 볼 수 있다. 또한 일부 프레임워크는 애플리케이션이 복잡해지면서 용량이 조금 더 빨리 증가했다.

그리고, 여기부터는 원본 글과 조금 다른 얘기를 하려고 한다. 우선 원본 글에서는 Addy Osmani의 2017년 글 The Cost of JavaScript와 Alex Russell의 2017년 글 Can You Afford It? Real-world Web Performance Budgets를 인용하여 페이지가 처음 로드될 때 읽어 들이는 모든 JS 파일 크기의 총합이 130kB 미만이어야 한다고 주장했다. Alex가 제시한 기준이 저속 네트워크에서 5초 안에 페이지가 나타나는 저성능 디바이스를 가정한 것이기 때문에 이 속도를 3초로 제한하면 허용된 JS 파일의 크기는 더 줄어들어서 70kB밖에 되지 않는다1주: 산술적으로는 130 x 3/5 = 78인데 원본글에서 70이라고 말한 이유는 정확히 알 수 없다.. 프레임워크 외에 사용할 써드파티 라이브러리 등이 최소 25kB는 될 것이므로 따라서 순수한 애플리케이션의 크기는 45kB로 제한된다. 프레임워크 자체의 크기가 큰 React를 기준으로 생각하면 TodoMVC 수준의 컴포넌트가 5개도 못 들어간다는 의미이다. 심지어 React Server Component를 사용하면 8kB의 추가 용량이 필요하다고 하니 원본글의 이 부분만 보면 React가 참 못 써먹을 프레임워크처럼 보인다.

그런데 지금은 2022년이다. 그 사이 전 세계의 모바일 인터넷 속도는 빠른 속도로 증가했다. 모바일 기준 2017년 11월에 Down: 20.28Mbps / Up: 8.65Mbps이던 평균 인터넷 속도는 2022년 4월에 Down: 74.87Mbps / Up: 14.29Mbps로 다운로드 속도만 보면 3.5배 이상 빨라졌다. 국내 한정으로 생각하면 숫자는 더 극적으로 변한다. 2022년 4월 기준 대한민국의 모바일 인터넷 속도는 Down: 243.07Mbps / Up: 23.22Mbps가 된다.

Alex Russell 또한 2021년에 작성한 글 The Mobile Performance Inequality Gap에서 최초 로딩시 JS 파일의 크기를 350kB로 3배 가까운 값으로 상향했다2다운로드 속도의 향상 비율과 거의 일치한다.. 3초를 기준으로 한다면 애플리케이션의 크기는 185kB로 Svelte 기준으로도 80개가 조금 안되는 TodoMVC가 들어갈 수 있다. 그리고 아마 이 정도 크기라면 어지간한 용도에는 크게 부족함이 없으리라 생각한다3우리나라 기준으로는 계산하지 않겠다. 인터넷 속도는 3배지만 사용자의 인내심은 1/3이라서 1초 내에 페이지가 표시되어야 할 것이기 때문이다.. 여기에 서버측 렌더링, 스트리밍, 캐시, 게으른 로딩 등의 (눈속임을 포함한) 다양한 기법이 더해지면 사용자의 불편은 최소화하면서도 애플리케이션의 크기는 더 늘릴 수 있을 것이다. 인터넷 기술의 발전에 따라 컴포넌트의 크기에 조금 덜 신경써도 되는, 그래서 프레임워크를 조금 더 자유롭게 선택할 수 있는 시기가 도래한 것이다.

이 글에서 보여준 결과가 프레임워크 간의 우열을 드러내는 것은 아니지만, 적어도 각 프레임워크가 적합한 상황을 찾는 데는 도움이 될 수 있다. 예를 들어, 용량이 몹시 중요하고 상대적으로 복잡하지 않은 애플리케이션이라면 Svelte의 사용을 고려해 볼 수 있을 것이다. 복잡한 애플리케이션이지만 용량이 중요한 환경이고 React에 익숙하다면 Preact를 대신 사용할 수도 있을 것이다.

각 프레임워크는 개발자가 중요하게 여긴 문제를 해결하며 성장해왔다. 사용자 역시 자신에게 잘 맞는 프레임워크를 선택하는 게 중요할 것이다. 이 글이 그 선택에 도움이 되었으면 좋겠다.

댓글을 남겨주세요

This site uses Akismet to reduce spam. Learn how your comment data is processed.