0
JS 번들 뚱뚱해지는 진짜 이유 3가지 - npm 의존성 다이어트 해야 할 때
frontend
요약
기사 전체 정리
- 레거시 엔진 지원: IE6급 구형 환경, 글로벌 네임스페이스 보호, 크로스-렐름(cross-realm) 이슈 때문에 `is-string` 같은 패키지가 생겨남
- 원자적 아키텍처: `path-key`, `is-wsl`, `slash` 같은 한 줄짜리 패키지들이 남발되면서 의존성 트리가 개복잡해짐
- Ponyfill 좀비화: `globalThis`, `Array.prototype.indexOf` 같이 이미 10년 전에 다 지원된 기능의 ponyfill이 아직도 수천만 다운로드 기록 중 ㄷㄷ
- 결국 극소수를 위한 설계가 모든 개발자한테 비용을 전가하는 구조가 문제
- knip, e18e CLI, npmgraph, module-replacements 프로젝트로 지금 당장 의존성 다이어트 가능
1. 레거시 런타임 지원 (크로스-렐름 & 안전성)
`is-string`, `hasown` 같은 패키지가 왜 존재하냐면 세 가지 이유가 있음:
① 구형 엔진 지원
`Array.prototype.forEach`, `Object.keys`조차 없는 ES3(IE6/7) 환경을 지원해야 하는 사람들이 있음. 뭐... 업그레이드하면 되지 않냐고 하고 싶지만ㅋㅋ
② 글로벌 네임스페이스 보호
Node.js 내부에서 쓰는 "primordials" 개념 - 누군가 `Map`을 재정의해도 Node 자체가 안 망가지도록 원본 참조를 따로 보관하는 방식. `math-intrinsics` 같은 패키지가 이 철학으로 만들어짐.
③ 크로스-렐름 값 처리
`<iframe>`에서 생성된 `RegExp`는 부모 페이지의 `RegExp`와 다른 클래스라 `instanceof` 체크가 실패함. 그래서 `Object.prototype.toString.call(val)`로 체크하는 패키지들이 생겨남. chai도 이 문제 있다고 함.
진짜 문제: 이런 니즈가 있는 사람은 극소수인데, 그 비용을 우리 모두가 내고 있는 거임 ㄹㅇ.
2. 원자적(Atomic) 아키텍처
"패키지는 최소 단위로 쪼개야 재사용 가능하다"는 철학으로 만들어진 패키지들:
- `arrify` - 값을 배열로 변환 (`Array.isArray(val) ? val : [val]`... 이게 패키지임)
- `slash` - 경로의 백슬래시를 `/`로 교체
- `path-key` - 현재 플랫폼의 PATH 환경변수 키 반환 (Unix: `PATH`, Windows: `Path`)
- `is-wsl` - WSL 환경 체크
- `is-windows` - `process.platform === 'win32'` 체크
왜 문제냐:
- 단일 소비자 문제: `shebang-regex`는 `shebang-command`에서만, `onetime`은 `restore-cursor`에서만 씀. 인라인 코드랑 다를 게 없는데 npm 요청, tar 압축 해제, 대역폭 비용은 다 냄
- 중복 버전 난무: nuxt 의존성 트리만 봐도 `is-docker`, `is-stream`, `path-key` 등이 버전 2개씩 들어있음 ㅋㅋ
- 공급망 공격 표면 확대: 패키지 많을수록 해킹 포인트도 많아짐. 실제로 이 패키지들 관리자 한 명이 작년에 해킹당해서 수백 개 패키지가 동시에 털렸음 ㄷㄷ
3. 폰어필(Ponyfill)의 좀비화
Ponyfill이란? 환경을 오염시키지 않는 폴리필. `import`해서 쓰는 방식이라 라이브러리에서 써도 안전함.
문제는 이미 모든 엔진이 기능을 지원하는데도 아무도 제거를 안 했다는 것:
- `globalthis` - 2019년부터 전 브라우저 지원, 지금도 주당 4,900만 다운로드
- `indexof` - 2010년부터 지원, 주당 230만 다운로드
- `object.entries` - 2017년부터 지원, 주당 3,500만 다운로드
그냥 아무도 안 지운 거임. 레전드급 관성ㅋㅋ
그래서 뭘 할 수 있냐
🔧 지금 당장 쓸 수 있는 도구들:
- **knip** - 미사용 의존성, 데드코드 탐지
- **e18e CLI** - `analyze` 모드로 대체 가능한 패키지 탐지 + `migrate` 명령어로 `chalk → picocolors` 같은 마이그레이션 자동화
- **npmgraph** - 의존성 트리 시각화. ESLint의 `find-up` 브랜치처럼 고립된 비대 의존성 발견 가능
- **module-replacements** - 네이티브 대체재나 더 나은 패키지 데이터셋. codemods도 제공
💡 할 수 있는 것:
- 직접 의존성 보면서 "이게 왜 있지?" 질문하기
- 불필요해 보이면 maintainer한테 issue 올리기
- 문제 많은 패키지는 대안 찾기 (module-replacements 참고)
댓글
댓글
댓글을 불러오는 중...