FE Study/Next.js

[Next] Next 패키지 최적화(optimizePackageImports)

jae1004 2024. 4. 5. 03:16

최근에 Next 공식 문서에서 우연히 보게 된 패키지 import 최적화에 대해 소개해 보겠습니다. 이 Vercel 글은 블로그는 패키지 최적화를 어떻게 진행했는지에 대해 설명하고 있습니다. 이 글을 기반으로 블로그를 작성해 보려고 합니다.

 

How we optimized package imports in Next.js – Vercel

How solving barrel files led to faster cold boots and build times.

vercel.com

 

밑의 블로그는 위의 글을 번역해 주신 글입니다!🙇‍♀️

 

(번역) Next.js에서 패키지 가져오기를 최적화한 방법

원문 : https://vercel.com/blog/how-we-optimized-package-imports-in-next-js40% 더 빨라진 콜드 부팅 및 28% 더 빨라진 빌드 속도최신 버전의 Next.js에서는 패키지 가져오기를 최적화했습니다. 이로

velog.io

첫 번째로 배럴 파일에 대해 설명해 보겠습니다.

배럴(Barrel) 파일이란?

JavaScript에서 하나의 파일에서 여러 모듈을 그룹화해 내보내는 방법입니다. 

이를 사용하면, 그룹화된 모듈에 액세스 할 수 있는 중앙화된 위치를 제공해 그룹화된 모듈을 더 쉽게 가져올 수 있습니다.

 

다음과 같은 폴더가 있을 때,

📂project
 ┣ 📜module1.js
 ┣ 📜module1.js
 ┗ 📜module1.js

 

배럴 파일이 없으면, 모듈을 개별적으로 가져와야 합니다.

배럴 파일이 없을 때
import module1 from "./project/module1";
import module2 from "./project/module2";
import module3 from "./project/module3";

 

배럴 파일이 있으면, 내부 구조에 대해 알 필요 없이 모든 모듈을 일괄적으로 가져올 수 있습니다.

배럴 파일 (index.js) 생성
export { default as module1 } from "./module1"; // or export * from "./module1";
export { default as module2 } from "./module2";
export { default as module3 } from "./module3";
📂project
 ┣ 📜module1.js
 ┣ 📜module1.js
 ┣ 📜module1.js
 ┗ 📜index.js // 배럴 파일
배럴 파일이 있을 때
import { module1, module2, module3 } from './project';

배럴 파일 사용의 이점

  • 관련 모듈에 쉽게 접근할 수 있어 코드 구성과 유지 보수성이 향상됩니다.
  • 모듈이 많은 대규모 프로젝트에서 import 프로세스를 구성하고 단순화하는데 유용합니다.

배럴 파일 사용의 문제점

  • 많은 항목들을 가져오는 배럴 파일에서 단일 내보내기를 사용할 경우, 불필요한 다른 모듈을 가져오기 때문에 사용하는 모듈 외에 추가 파일을 처리해야 하는 문제가 발생해 성능 저하가 발생할 수 있습니다.
  • import 프로세스에 또 다른 간접 계층을 추가하므로 특정 값의 출처를 이해하기 어려워질 수 있어 복잡성이 증가합니다.

 

 

 

다음으로는 일반적으로 패키지 최적화를 수행할 경우 사용하는 방법인 트리 셰이킹(Tree-shake)에 대해 간단히 설명하고, 왜 Next에서는 이 방법을 사용하지 않았았는지에 대해서 다루어보겠습니다.

트리 쉐이킹(Tree-shake)을 사용하지 않은 이유

Tree Shaking은 간단히 말해서 번들에서 사용되지 않는 코드를 제거하여 패키지 크기를 최적화하는 기술입니다. 이는 webpack, rollup, esbuild 등과 같은 Bundler의 기능입니다. Bundler는 런타임에 종속성이 필요하기 때문에 이 라이브러리 내부에서 최적화를 수행할 수 없습니다. 모든 모듈을 컴파일하고 분석해야 하므로 런타임 종속성이 있는 라이브러리의 경우 복잡하고 느리기 때문에, Next.js는 트리 쉐이킹을 하지 않는 다른 방법을 선택했습니다.

첫 번째 시도: modularizeImports

modularizeImports 옵션을 사용하면 내보낸 이름과 패키지의 배럴 파일 뒤에 있는 원래 모듈 경로의 매핑 관계를 구성할 수 있습니다. 이 말은 즉,  두 번째 코드처럼 배럴 파일을 건너뛰고 대상에서 직접 import 하여 불필요한 모듈을 로드하지 않도록 할 수 있습니다. 이러한 변경으로 인해 빌드 시간과 런타임이 모두 빨라졌다고 설명하고 있습니다. (배럴 파일 설명의 폴더 구조 참고)

import { module2 } from './project';
import module2 from "./project/module2";

하지만 이 방식에는 치명적인 단점이 있습니다. 라이브러리의 내부 디렉터리 구조를 기반으로 해, 대부분 수작업으로 구성되기 때문에 효율적으로 확장할 수 있는 방법이 없고, 라이브러리의 내부 구조가 변경되면 무효화가 됩니다.

해결책: optimizePackageImports

이 방식은 modularizeImports 옵션 구성의 어려움을 해결하기 위해 도입되었다고 합니다.

next.config.js
module.exports = {
  experimental: {
    optimizePackageImports: ['package-name'], // 패키지 이름 작성
  },
}

 

 

next.config.js Options: optimizePackageImports | Next.js

API Reference for optmizedPackageImports Next.js Config Option

nextjs.org

이렇게 옵션을 활성화하면 Next.js가 해당 패키지의 진입 파일을 분석하고 배럴 파일인 경우, moduleizeImports 작동 방식과 유사하게 즉시 파일을 분석하고 모든 import를 자동으로 매핑합니다.

 

이 방법은 한 번에 항목 배럴 파일만 확인해 트리 쉐이킹보다 비용이 저렴하고, 중첩된 배럴 파일과 와일드카드 내보내기(export

* from)를 재귀적으로 처리하고, 배럴이 아닌 파일에 부딪치면 프로세스를 종료합니다.

 

또한 이 옵션은 패키지 내부 구현에 의존하지 않습니다.

성능 개선 측정

 

성능 개선 측정 결과

위의 이미지에서 볼 수 있듯이 아이콘 또는 컴포넌트 라이브러리 중 하나를 사용할 경우, 라이브러리에 따라 개발 시간이 15% ~ 70% 단축된다고 합니다. 프로덕션 빌드 시에도 약 28% 더 빠르게 실행된다고 합니다!

 

자세한 사항은 블로그 내용을 참고하시면 좋을 것 같습니다!!

728x90