[Next.js] Tiptap에 이미지 추가하기(Cloudinary)

이크·2024년 7월 30일

nextjs

목록 보기
5/9

지난 포스트에 이어서 이번엔 Tiptap에 이미지를 등록하고 저장할 것이다. 이미지 클라우드는 Cloudinary를 사용한다.

이미지 추가하기

Tiptap에서 이미지를 추가하려면 image extension을 따로 추가해 주어야 한다. Image extension 을 추가해서 editor에 등록하면 이미지를 사용할 수 있다.

https://tiptap.dev/docs/editor/extensions/nodes/image

import Image from "@tiptap/extension-image";
...
const editor = useEditor({
    extensions: [
      StarterKit.configure({
        heading: {
          levels: [1, 2, 3],
        },
      }),
      Underline,
      Image.configure({
        allowBase64: true,
      }),
	...
    ],
  ...
})

allowBase64를 true로 설정하여 이미지를 base64 string으로 파싱되도록 했다. 이렇게 설정하면 이미지를 업로드 할 수 있다. 이미지 업로드 등록 버튼은 ToolBar에 추가했다.

// Toolbar.tsx

<input
  type="file"
  accept="image/*"
  ref={fileInputRef}
  onChange={handleFileChange}
  hidden
    ></input>
  <FileImage
  className="w-5 h-5 text-sky-400 hover:text-sky-700"
  onClick={fileInputHandler}
  />

input 태그를 이용해서 이미지 파일을 업로드 하면 editor에 정상적으로 이미지가 추가된다. submit을 해보면 아래와 같은 결과가 나온다.

content: "<p><strong>base64 테스트</strong></p><p></p><img src=\"data:image/png;base64,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\">"
title: "테스트입니다."

보다시피 이미지가 base64 string으로 parsing 되어 있다. 이 상태로 DB에 저장해도 정상적으로 이미지가 로드되지만, 나는 이미지는 클라우드에 따로 저장하고 img의 src를 클라우드 경로로 지정하고 싶다. 기존에 DB에 저장하는 객체는

const post = {
  title: title,
  content: xss(content),
  created_at: new Date(),
  updated_at: new Date(),
};

이렇게 되어 있었다. DB에 저장하기 전 content 값을 수정해서 이미지를 저장할 것이다.

	const imgTagRegex = /<img[^>]+src="data:image\/[^">]+"/g;
    let match;
    const imageUploads: Promise<string>[] = [];

    // content에서 모든 이미지 URL을 추출
    while ((match = imgTagRegex.exec(content)) !== null) {
      const imgTag = match[0];
      const base64ImageMatch = imgTag.match(/src="data:image\/[^">]+"/);

      if (base64ImageMatch) {
        const base64Image = base64ImageMatch[0].split('"')[1];
        imageUploads.push(uploadImageToCloudinary(base64Image));
      }
    }

    const imageUrls = await Promise.all(imageUploads);
    console.log(imageUrls);

    let updatedContent = content;
    let urlIndex = 0;

    updatedContent = updatedContent.replace(imgTagRegex, (match) => {
      const base64ImageMatch = match.match(/src="data:image\/[^">]+"/);
      if (base64ImageMatch) {
        const base64Image = base64ImageMatch[0].split('"')[1];
        const cloudinaryUrl = imageUrls[urlIndex++];
        return match.replace(base64Image, cloudinaryUrl);
      }
      return match;
    });

    const post = {
      title: title,
      content: xss(updatedContent),
      created_at: new Date(),
      updated_at: new Date(),
    };

	...

content에서 base64 값을 모두 가져와 Cloudinary에 저장한 후 이를 다시 content 내의 img 태그 src랑 replace해서 객체에 저장했다. 아래는 Cloudinary에 저장하는 코드이다.

// cloudinary.ts

import { v2 as cloudinary } from "cloudinary";

cloudinary.config({
  cloud_name: process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,
  api_key: process.env.NEXT_PUBLIC_CLOUDINARY_API_KEY,
  api_secret: process.env.CLOUDINARY_API_SECRET,
});

export async function uploadImageToCloudinary(
  base64Image: string
): Promise<string> {
  try {
    const base64Data = base64Image.split(",")[1]; // 데이터 URL에서 Base64 데이터 추출
    const buffer = Buffer.from(base64Data, "base64"); // Base64 데이터를 Buffer로 변환

    // Cloudinary에 업로드
    const result = await new Promise<any>((resolve, reject) => {
      cloudinary.uploader
        .upload_stream({ resource_type: "image" }, (error, result) => {
          if (error) {
            return reject(error);
          }
          resolve(result);
        })
        .end(buffer);
    });

    return result.secure_url;
  } catch (error) {
    console.error("Error uploading image to Cloudinary", error);
    throw new Error("Failed to upload image to Cloudinary");
  }
}

base64 string을 받아와서 Cloudiary에 업로드 후 해당 이미지의 url을 return 하는 형식으로 구성하였다. 이렇게 하면 content에는 이러한 결과가 저장된다.

<p>안녕하세요 <strong>Cloudinary 테스트</strong></p><img src="https://res.cloudinary.com/ekrtionl-guam/image/upload/v1722331390/w0s6ium9nlfhqxs1fu5l.jpg">

그리고 화면에 출력하면 정상적으로 이미지가 출력된다.

profile
뭐라도 해보자

0개의 댓글