모바일 카메라 사진 업로드 충돌, browser-image-compression으로 해결
모바일에서 사진 업로드 동작을 만들다가, 데스크톱에서는 멀쩡하던 업로드가 모바일에서만 가끔 무너지는 케이스를 마주쳤다. 카메라로 찍은 사진을 올릴 때만 발생해서, 원인을 따로 짚고 회피 방법을 찾았다.
사진 찍기 경로만 유독 브라우저가 죽었다
모바일에서 <input type="file" accept="image/*">를 누르면 사진 보관함에서 고르기, 사진 찍기, 파일 탐색기 같은 선택지가 뜬다. 보관함이나 파일 탐색으로 고른 사진은 문제없이 올라갔는데, "사진 찍기"로 그 자리에서 촬영한 사진만 업로드 직전에 브라우저가 통째로 멈추거나 탭이 죽었다.
원인은 단순했다. 요즘 모바일 카메라는 해상도가 워낙 높아서 결과 파일이 수십 MB까지 나온다. 그 크기를 그대로 메모리에 올려두고 미리보기와 업로드를 같이 돌리니 모바일 브라우저가 버티지 못했다. 보관함에서 고른 사진은 이미 압축돼 있는 경우가 많아 같은 문제가 잘 안 보였던 거였다.
browser-image-compression으로 업로드 전에 한 번 줄였다
업로드 전에 파일을 클라이언트에서 한 번 줄이면 되는 문제라, browser-image-compression을 가져다 썼다. 파일 입력의 onChange에서 선택된 File을 꺼내, imageCompression(file, options)에 그대로 넘기면 압축된 새 File이 돌아온다.
import imageCompression from 'browser-image-compression';
const handleChange = async (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (!file) return;
const options = {
maxSizeMB: 1,
maxWidthOrHeight: 1920,
useWebWorker: true,
};
const compressed = await imageCompression(file, options);
// 이후 압축된 file을 서버로 업로드
};옵션은 README 기준으로 maxSizeMB(상한 용량), maxWidthOrHeight(긴 변 기준 리사이즈), useWebWorker(메인 스레드 부하 분산) 정도가 핵심이었다. 특히 useWebWorker: true는 이번처럼 모바일 충돌이 문제일 때 자연스러운 선택이었다. 압축 자체가 메인 스레드에서 돌면 그 사이에 UI가 같이 굳기 때문에, 워커로 빼내야 화면이 멈추지 않는다.