npm 의존성 트리가 부풀어 오르는 세 가지 주요 이유
JavaScript 프로젝트의 의존성 트리는 종종 오래된 패키지와 중복된 플랫폼 기능 때문에 비대해집니다. 이로 인해 불필요한 다운로드 비용, 버전 충돌, 공급망 취약점이 발생합니다. 이 상황을 설명하는 세 가지 전형적인 시나리오와 해결 방법을 살펴보겠습니다.
레거시 환경 지원 및 영역별 문제
is-string이나 hasown 같은 많은 패키지는 ES3(IE6/7, 초기 Node.js) 같은 오래된 런타임과의 호환성을 위해 존재합니다. 이들은 누락된 메서드(Array.prototype.forEach, Array.prototype.reduce, Object.keys, Object.defineProperty)를 구현합니다.
추가적인 이유:
- 전역 네임스페이스 보호: Node는 오버라이드로 인한 오류를 방지하기 위해 프리미티브(예:
Map)를 임포트합니다.math-intrinsics같은 패키지는 비슷한 목적으로Math.*를 재내보냅니다. - 영역 호환성:
instanceof는 iframe과 부모 간에 작동하지 않습니다(다른RegExp생성자). 대안으로Object.prototype.toString.call(val) === '[object RegExp]'를 사용하며,chai나is-string에서new String(val)에 활용됩니다.
const shebangRegex = /^#!(.*)/;
export default shebangRegex;
대부분의 중급 이상 개발자에게 이는 과도한 작업입니다: 최신 Node(10년 이내)와 브라우저는 이런 해킹이 필요하지 않습니다. 권장사항: browserslist를 확인하고 불필요한 폴리필을 제거하세요.
원자적 아키텍처: 이론에서 문제까지
'원자적' 패키지 철학은 코드를 재사용 가능한 최소 블록으로 분해하는 것을 포함합니다. 예를 들어 execa의 의존성 그래프는 shebang-regex(5줄 코드) 같은 패키지를 포함합니다.
전형적인 원자적 유틸리티:
arrify:Array.isArray(val) ? val : [val]slash: 경로 슬래시 정규화cli-boxes: UI 요소 테두리를 위한 JSONpath-key:env['PATH'] || env['Path']onetime: 일회성 함수 호출is-wsl:process.platform === 'linux' && /microsoft/.test(os.release())is-windows:process.platform === 'win32
이론적으로 이는 CLI 구축을 단순화합니다. 실제로는:
- 일회성 사용:
shebang-regex는shebang-command(동일 저자)에서만 사용됩니다;cli-boxes는boxen/ink에서만 사용됩니다. - 호이스팅 중복:
nuxt에서is-docker,is-stream,is-wsl(각 2개 버전) 같은 중복이 발생합니다. 인라인 코드는 npm 오버헤드 없이 무료로 중복됩니다. - 공급망 위험: 더 많은 패키지는 더 많은 취약점을 의미합니다. 한 유지 관리자가 손상되면(작년에 발생한 사례) 수백 개의 의존성이 영향을 받습니다.
해결책: 간단한 함수를 인라인화하고, 트리 셰이킹을 사용하며, 엄격한 호이스팅이 있는 pnpm을 활용하세요.
시대를 초월한 포니필
포니필은 전역을 변형하지 않고 직접 임포트하는 폴리필입니다. 라이브러리에 유용합니다: @fastly/performance-observer-polyfill은 환경을 변경하지 않고 PerformanceObserver를 사용할 수 있게 합니다.
문제: 네이티브 지원이 도래한 후 제거되지 않습니다.
오래된 포니필 예시(주간 다운로드 포함):
globalthis—globalThis용(2019년부터 지원, 주간 49M 다운로드)indexof—Array.prototype.indexOf용(2010년부터 지원, 주간 2.3M 다운로드)object.entries—Object.entries용(2017년부터 지원, 주간 35M 다운로드)
eslint-plugin-react에서 그래프의 절반은 레거시 폴리필로 구성됩니다. 라이브러리의 경우: 소비자 측 폴리필(core-js)에 의존하세요. 추가 전에 caniuse.com을 확인하세요.
핵심 요약
- 레거시 최적화: 90%의 패키지는 ES3/ES5 폴리필이 필요하지 않습니다;
is-string대신typeof를 사용하세요. - 원자성의 해로움: 5줄 함수를 인라인화하여 중복과 공격 표면을 줄이세요.
- 포니필 감사: 대상 런타임에서 5년 이상 지원된 기능을 위한 패키지를 제거하세요.
- 도구: 분석을 위해
npm ls --depth=0,depcheck,npm-check-updates를 사용하세요. - e18e 이니셔티브: 성능을 위해 오래된 의존성 정리에 집중하세요.
실용적인 정리 단계
npm dedupe와npm prune을 실행하세요.- 강제 호이스팅을 위해
package.json에overrides를 추가하세요. - 트리 셰이킹이 있는
esbuild/vite를 사용하세요. webpack-bundle-analyzer로 번들 크기를 모니터링하세요.
이렇게 하면 기능을 잃지 않고 번들 크기를 20-50% 줄일 수 있습니다.
— Editorial Team
아직 댓글이 없습니다.