home

Nextjs 13에서 barrel exports와 Tree Shaking 사이의 연관성

글 분류
main
키워드
nextjs
bundler
생성일
2023/03/17 00:05
최근 수정일
2024/12/08 08:01
작성중
글 작성 시 사용한 Nextjs 버전 → 13.2.4 현재 프로젝트와 비교를 위해 traspiler는 swc가 아닌 babel로 사용

⚽️ 목표

barrel exports 시 tree shaking이 이루어지는 기준을 확인
여러 가지 변수가 존재하는데 반복 노가다해서 전부다 바꿔서 수정하고 이거수정하고…으아ㅏㅏ

TL;DR

barrel exports는 필수가 아닌 선택입니다..
반박 시 당신이 맞습니다…ㅠㅠ
barrel exports는 개인적으로 코드 가독성 + 관리성 면에서 좋았다. → 필수 아님
번들링 시 Tree Shaking에 악영향을 끼칠 가능성이 있다. → 현재 사용하고 있는 환경 + 번들러 버전 및 종류 + 프레임워크 버전 및 종류에 따라 결과물이 천차만별로 다를 수 있기 때문에 꼭 테스트 후 적용해야 한다!!!
생각보다 webpack과 같은 번들러는 똑똑하게 작동해 treeshaking 하지만 너무 믿지말자!
barrel exports는 생각보다 번들용량에 크게 영향을 끼치지 않는다.

들어가기 전에 - barrel exports가 뭐니?

테스트 환경

nextjs 기반의 프로젝트에서 테스트 했다. - 13.2.4
회사 프로젝트에 맞춰 swc가 아닌 babel 사용했다. 모든 항목을 테스트해본건 아니지만 swc에서도 큰 차이를 보이진 않았다.

page1.tsx, page2.tsx

// src/pages/page1.tsx export default function Test1() { return ( <h1>Test1 page</h1> ); } // src/pages/page1.tsx export default function Test2() { return ( <h1>Test2 page</h1> ); }
TypeScript
복사
page1.tsx, page2.tsx 파일 두개로 나뉘어 서로 다른 case로 나누어 tree-shaking이 발생하는 케이스를 확인할 예정이다.

func1.ts,func2.ts

// testFunc1, 1_1, 1_2, 2 모두 같은 함수 export const testFunc1 = () => { const longString = "239828932903i198ewfhp98q34h23982893290 // 아주 긴 문자열 return `${longString}320390`; };
TypeScript
복사
간단히 아주 긴 문자열 끝에 다른 문자열을 붙여서 반환하는 일을 하는 함수
func1.ts에는 testFunc1, testFunc1_1, testFunc1_2가 존재한다.
testFunc1만 사용하고 나머지를 사용 안할 경우? 와 같은 엣지 케이스를 테스트하기 위해 여러 함수를 생성했다.
func2.ts에는 testFunc2 만 존재한다.
webpack 버전, 프레임워크 버전 코드방식에 따라 테스트 결과가 상이하다. 본인의 환경에서 테스트 결과를 제대로 확인해보자.
“하나의 함수가 page A, page B에서 동시에 사용될 경우 tree-shaking은 어떻게되는가?”에 대한 복잡한 상황에 대한 테스트 결과가 아니다. 해당 사항은 후에 기술한다.

비교 1. barrel exports의 기본적인 tree-shaking 여부 확인

테스트 과정

func1.tstestFunc1, testFunc1_1, testFunc1_2 모두 존재하는 상황이다.
page1.tsx, page2.tsx는 기본상태 → 아무 함수도 import하지 않았다.
utils 디렉터리의 barrel exports 여부로 인한 트리쉐이킹 여부를 확인한다.

결과

함수 생성 후 페이지에서 미사용 시 - tree-shaking
함수 생성 후 barrel exports 후 페이지에서 미사용 시 - tree-shaking

테스트 상세 과정

webpack은 생각 보다 똑똑하다

비교 2. 같은 파일 내에 존재하는 함수 하나만 사용할 경우 tree-shaking 여부 확인

테스트 과정

page1.tsx에 아래코드를 추가한다.
import { testFunc1 } from "@/utils"; export default function Test1() { return ( <h1 onClick={testFunc1}>Test1 page</h1> ); }
TypeScript
복사
page2.tsx는 기본상태
func1.ts에 함수가 하나만 있을 경우 또는 두개있을 경우에 대한 용량 테스트를 위해 확인
케이스1 에는 testFunc1만 존재한다.
케이스2 에는 testFunc1, testFunc1_1, testFunc1_2 둘다 존재한다.
export const testFunc1 = () => { const longString = "239828932903i198 // 생략 } export const testFunc1_1 = () => { const longString = "239828932903i198 // 생략 }
TypeScript
복사

결과

func1.ts에 다른 함수들(testFunc1_1, testFunc1_2)이 존재하나 페이지에서 testFunc1만 사용할 경우 - tree-shaking
testFunc1만 import된 상태로 번들링이 수행된다.

테스트 상세 과정

비교 3. 같은 함수를 여러군데에서 사용했을 경우

테스트 과정

page1.tsx, page2.tsx 두 파일에 똑같은 함수인 testFunc1을 import 후 사용했을 때의 build analyzer 결과물과 page1.tsx에만 import 후 사용했을 때의 build analyzer 결과물을 비교할 예정이다.
테스트 결과의 가독성을 위해 테스트 함수의 크기를 아주크게 늘렸다.
// page1.tsx - 테스트 1,2 모두 import { testFunc1 } from "@/utils"; export default function Test1() { // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions return <h1 onClick={testFunc1}>Test1 page</h1>; } // page2.tsx - 테스트 1 import { testFunc1 } from "@/utils"; export default function Test2() { // eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions return <h1 onClick={testFunc1}>Test2 page</h1>; } // page2.tsx - 테스트 2 export default function Test2() { return ( <h1>Test2 page</h1> ); }
TypeScript
복사

결과

page1.tsx에서만 사용할 경우 해당 파일은 page1.tsx에 종속된다. → 번들링된 해당 페이지 파일 내부에
번들링 시 두개 이상의 파일에서 사용하는 코드모음을 가지고있는 새로운 js 파일을 생성해 코드 중복을 제거한다.
번들러는 역시 생각 보다 똑똑해요!

테스트 상세 과정

결론

nextjs13(babel 기반)에서 barrel exports는 번들링 결과물에 영향을 끼치지 않는다.
우리들의 번들러는 생각보다 똑똑하다. → 알아서 나[눠주고 알아서 tree-shaking하며 최적의 번들링 결과물을 제공한다.
하지만 이런 번들러도 버전마다, 설정마다, 파일 나눔의 기준, tree-shaking의 기준이다르다. 번들러를 너무 믿지마라. 똑똑하지만 살짝 뒤떨어지는 동네형 같은 느낌적인 느낌으로 대해줘야 한다.

참조