react quill 텍스트 에디터 이미지 업로드 느림

김민지·2026년 1월 4일

인턴 정리

목록 보기
1/7

텍스트 에디터에 이미지 뜨는 속도가 느리다는 이야기를 듣고...
직접 해보니 (당연하지만) 큰 이미지 올리면 속도가 느려지더라.
그러면 뭐 이미지 압축하고, 유저에게는 그 동안 이미지를 어떻게든 미리 보여줘야겠지?

참고로 지금 문제가 되는 이미지 크기는 9.15MB다. 크긴 커~

일단 지금은
사용자가 이미지를 선택하면
useFileUpload 훅이 이미지를 FormData로 API에 올린다.
서버가 응답으로 이미지의 url을 반환해주는데 이 값을 프론트에서 img 태그에 넣어서 보여준다.

그러니까 서버에 업로드가 끝나야 url을 받을 수 있는거고, 근데 사용자 입장에선 지금 내가 업로드한 사진을 바로 보고 싶어서 문제가 생긴거다.

내가 알기로는 Canvas를 쓰면 라이브러리 없이 이미지를 압축할 수 있는데, 나는 라이브러리 안 쓰고 싶어서... 그니까 원리를 조금이라도 살펴보고 싶어서 한 번 canvas로 먼저 써보기로 했다. 별로면 라이브러리로 바꾸고~~

그래서
canvas를 만들고, 최대 너비를 제한하고, 그에 맞춰 이미지 크기를 줄여서 압축된 이미지를 반환하도록 했다.

...생략
      const img = new Image();
      const reader = new FileReader();

      reader.onload = e => {
        img.src = e.target?.result as string;
      };

      img.onload = () => {
        const canvas = document.createElement('canvas');
        const MAX_WIDTH = 1024;

        let width = img.width;
        let height = img.height;

        if (width > MAX_WIDTH) {
          height *= MAX_WIDTH / width;
          width = MAX_WIDTH;
        }

        canvas.width = width;
        canvas.height = height;

        const ctx = canvas.getContext('2d');
        ctx?.drawImage(img, 0, 0, width, height);

        canvas.toBlob(
          blob => {
            const compressedFile = new File([blob!], file.name, {
              type: 'image/jpeg',
              lastModified: Date.now()
            });
            resolve(compressedFile);
          },
          'image/jpeg',
          0.7 

...생략

꽤나 빨라졌다.
근데 이미지 복붙해서 넣는 경우는 여전히 느려서 복붙하는 경우를 따로 처리를 해주기로 했다.

  React.useEffect(() => {
    const handlePaste = async (event: ClipboardEvent) => {

      const items = event.clipboardData?.items;
      if (!items) return;

      let handled = false;

      for (const item of items) {
        if (item.kind === 'file' && item.type.startsWith('image/')) {
          const file = item.getAsFile();
          if (file && !handled) {
            handled = true;

            const compressed = await compressImageWithCanvas(file);
            setFileObj(compressed);
            event.preventDefault();
          }
        }
      }
    };
    window.addEventListener('paste', handlePaste);

    return () => {
      window.removeEventListener('paste', handlePaste);
    };
  }, []);

아 근데 이미지 하나 복붙해도 두 개가 뜨는 문제가 발생했다. (텍스트 에디터에서 이미지 업로드할 때는 정상 동작함)

이미지 복붙 테스트하면서 알게된건데
컴퓨터에서 이미지 파일을 열어서 이미지 우클릭해서 복붙하는거랑 인터넷에서 이미지 복붙해서 넣는거랑 다르다고 한다...

그래서 그런지 전자는 같은 이미지가 두 개 뜨지만

후자는 위쪽 이미지가 아이콘으로 뜬다.

이미지 두 개 들어가는 건 event.preventDefault();
를 넣어주면 된다.
왜냐면 복붙한거 그대로 붙이는 것(default)이랑 압축한거랑 둘 다 붙여넣어져서 default를 방지해야 하기 때문이다.

...생략
  React.useEffect(() => {
    const handlePaste = async (event: ClipboardEvent) => {
      event.preventDefault();
...생략

그래서.. 이렇게 문제 상황은 해결 되었고
정확히 얼마나 빨라졌는지 performance.now()로 측정해보았다.

아래처럼 파일 선택 시점 시간 저장하고

업로드가 끝나는 시간 저장해서 계산했다.

무려 12529.800000071526 ms... 12.53초다...

개선 결과
1. 텍스트 에디터에 이미지 파일 업로드 속도
2404.899999976158 ms, 그러니까 2.4초

  1. 인터넷에서 이미지 복붙하는 속도
    1617.8000000715256 ms, 그러니까 1.61초

  2. 파일탐색기에서 이미지 파일 열어서 복붙하는 속도
    2567.5 ms, 그러니까 2.56초

더 줄일라면 줄일 수 있겠지만, 다른 작업들도 해야 해서 여기까지.
아주 만족스럽다.

profile
이건 대체 어떻게 만든 거지?

0개의 댓글