Node.js 18 LTS로 마이그레이션하면서 겪은 fetch API 관련 이슈
배경
회사 프로젝트에서 사용하던 Node.js 16이 올해 9월이면 메인터넌스 모드로 전환된다. Node.js 18이 지난 4월에 릴리즈되었고, 이번 10월에 LTS로 전환될 예정이라 미리 마이그레이션을 진행했다.
문제 상황
Node.js 18의 가장 큰 변화는 Web Streams API와 fetch API가 기본 내장되었다는 점이다. 그런데 프로젝트에서 기존에 사용하던 node-fetch 패키지와 타입 정의가 충돌하는 문제가 발생했다.
// 기존 코드
import fetch from 'node-fetch';
const response = await fetch('https://api.example.com/data');
const data = await response.json();
타입스크립트 컴파일 시 Response 타입이 글로벌 타입과 node-fetch의 타입 양쪽에 존재해서 에러가 발생했다.
해결 방법
1. node-fetch 제거
가장 단순한 방법은 node-fetch를 제거하고 내장 fetch를 사용하는 것이다.
npm uninstall node-fetch @types/node-fetch
// 수정된 코드 - import 제거
const response = await fetch('https://api.example.com/data');
const data = await response.json();
2. 타입 정의 문제
@types/node를 18 버전으로 업데이트해야 fetch 관련 타입이 제대로 인식된다.
npm install -D @types/node@18
3. 레거시 코드 처리
일부 유틸 함수에서 node-fetch의 Response 타입을 직접 사용하고 있었다. 이를 전역 Response 타입으로 변경했다.
// Before
import { Response } from 'node-fetch';
async function handleResponse(res: Response) {
// ...
}
// After
async function handleResponse(res: Response) {
// 전역 Response 타입 사용
}
주의사항
Node.js 18의 fetch는 experimental이 아니지만, 일부 옵션은 아직 지원하지 않는다. 특히 agent 옵션을 사용한 커스텀 HTTP 설정이 필요하면 undici를 직접 사용하는 게 낫다.
결과
의존성 하나를 줄이고 네이티브 API를 사용하게 되어 번들 사이즈도 약간 줄었다. 다만 팀원들에게 Node.js 18 환경 세팅을 요청해야 했고, CI/CD 파이프라인의 Node 버전도 함께 업데이트했다.