@Joonmook
sharp 0.35가 Node 18에서 안 돌았다: 네이티브 모듈과 런타임 버전
업로드 이미지를 WebP로 줄이려고 sharp를 붙였다. 로컬에서는 잘 됐다. 배포하고 나서 서버 로그를 보니 이렇게 찍혀 있었다.
Could not load the "sharp" module using the linux-x64 runtime
Possible solutions:
- Please upgrade Node.js:
Found 18.19.1
Requires >=20.9.0
서버는 Ubuntu 24.04에 apt로 깐 Node 18이고, 로컬은 Node 25다. sharp 0.35부터 최소 버전이 Node 20.9로 올라갔는데, 로컬에서 npm install 할 때는 당연히 아무 문제가 없었으니 알 길이 없었다.
경고는 있었다
정확히 말하면 알 길은 있었다. 서버에서 npm install 을 돌릴 때 이런 경고가 나왔다.
npm WARN EBADENGINE Unsupported engine {
npm WARN EBADENGINE package: 'sharp@0.35.4',
npm WARN EBADENGINE required: { node: '>=20.9.0' },
npm WARN EBADENGINE current: { node: 'v18.19.1', npm: '9.2.0' }
npm WARN EBADENGINE }
EBADENGINE은 경고지 에러가 아니다. 설치는 그냥 된다. 그리고 배포 스크립트 출력에서 경고 열 줄은 아무도 안 읽는다. 나도 안 읽었다. 순수 JS 패키지라면 engines 필드가 틀려도 대부분 돌아가니까 경고로 두는 게 맞는데, 네이티브 모듈은 다르다. 미리 빌드된 바이너리가 특정 Node ABI에 묶여 있어서 런타임에 require 하는 순간 터진다.
서비스가 안 죽은 이유
다행히 블로그는 계속 떠 있었다. sharp를 불러오는 코드를 이렇게 감싸뒀기 때문이다.
let sharp = null;
try {
sharp = require('sharp');
} catch (err) {
console.warn('sharp 를 불러오지 못해 이미지 최적화를 건너뜁니다:', err.message);
}
// ...
if (!sharp) return file; // 최적화 없이 원본 저장
이미지 최적화는 있으면 좋은 기능이지 없으면 서비스가 멈춰야 하는 기능이 아니다. 그래서 처음부터 "없으면 건너뛴다"로 짰다. 이 한 줄 덕분에 배포 직후 사이트는 멀쩡했고, 나는 로그를 보고 나서 고칠 시간을 벌었다. 부가 기능의 의존성은 항상 이렇게 격리하는 게 맞다고 다시 느꼈다.
고친 방법
sharp 0.34 계열은 Node 18.17 이상을 지원한다. package.json에서 버전을 내렸다.
npm install "sharp@^0.34.5"
npm view 로 버전별 engines를 미리 확인하는 습관이 있었으면 처음부터 맞았을 거다.
npm view sharp@0.34.5 engines.node # ^18.17.0 || ^20.3.0 || >=21.0.0 npm view sharp@0.35.0 engines.node # >=20.9.0
진짜 문제는 Node 18이다
사실 sharp가 잘못한 건 없다. Node 18은 2025년 4월에 지원이 끝났다. 보안 패치도 더 안 나온다. 서버를 처음 세팅할 때 apt에 있는 걸 그냥 깔았고, 그 뒤로 한 번도 안 올렸다. 혼자 운영하는 서비스에서 흔한 일이다. 돌아가면 안 건드리게 되니까.
그래서 이번 일은 "sharp 버전 내리기"로 끝낼 게 아니라 "Node 올리기"로 끝내야 맞다. 다만 같은 서버에 다른 앱도 떠 있어서, 그건 시간을 잡고 따로 할 생각이다. 그전까지 0.34에 고정해두는 건 임시방편이라는 걸 package.json 주석으로 남겨뒀다.
그래서 나는
- 네이티브 모듈을 추가할 때는 서버의 Node 버전으로 engines를 확인한다. 로컬 설치 성공은 아무것도 보장하지 않는다.
- 부가 기능의 의존성은 없어도 서비스가 도는 구조로 격리한다. 이번에 이게 나를 살렸다.
- 배포 스크립트에서 EBADENGINE 경고를 에러로 승격시키는 걸 고려 중이다. npm 설정으로는 engine-strict 가 있다.
- Node 18은 올해 안에 올린다. 이 글이 그 약속의 기록이다.
Comments 0
No comments yet. Be the first!