글 작성 시 사용한 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.ts에 testFunc1, 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의 기준이다르다. 번들러를 너무 믿지마라. 똑똑하지만 살짝 뒤떨어지는 동네형 같은 느낌적인 느낌으로 대해줘야 한다.