저는 Quill 에디터에서 커스텀 이미지 핸들러를 구현해, 이미지를 S3에 업로드한 뒤 서버로부터 이미지 URL과 ID를 전달받았습니다.
백엔드에서 이미지를 효율적으로 관리하려면 실제로 글에서 사용되는 이미지의 ID만 전달해야 했기 때문에, 최종 제출 시점에서 전체 데이터(Delta)를 순회해 현재 에디터에 남아 있는 이미지들의 ID만 추출해 서버에 전달하려고 했습니다.
하지만 기본 이미지 삽입은 단순히 url
만 설정할 수 있고, ID 값은 삽입할 수 없었습니다.
Custom Blot을 구현해 Quill의 img Blot 에 data-id
속성을 넣을 수 있도록 했습니다.
아래 코드처럼 구현하면 이미지 삽입 시 url
과 id
를 함께 넣을 수 있고, 컨텐츠(Delta)에도 두 값이 기록됩니다.
import Quill from 'quill';
import { BlockEmbed } from 'quill/blots/block';
// 커스텀 이미지 블롯 정의
class CustomImageBlot extends BlockEmbed {
static blotName = 'customImage'; // 델타에서 사용할 블롯 이름
static tagName = 'img'; // 실제 DOM에 삽입될 태그 (img 태그 사용)
// 에디터에 이미지 삽입할 때 호출되는 메서드
static create(value: { id: string; url: string }) {
const node = super.create() as HTMLElement; // 기본 img 요소 생성
node.setAttribute('src', value.url); // 이미지 URL 설정
node.setAttribute('data-id', value.id); // 추가 식별자(data-id) 설정
return node; // 최종 img 노드 반환
}
// 에디터로부터 델타(Delta)를 생성할 때 사용되는 메서드
static value(node: HTMLElement) {
return {
id: node.getAttribute('data-id'), // data-id 값을 델타에 포함
url: node.getAttribute('src'), // src 값을 델타에 포함
};
}
}
// 이미 같은 이름의 포맷이 등록되어 있는지 확인하고, 없다면 등록
if (!Quill.imports['formats/customImage']) {
Quill.register(CustomImageBlot); // 커스텀 이미지 블롯을 Quill에 등록
}
게시물 내용을 보여줄 때는 quill-delta-to-html
라이브러리를 사용해 Delta를 HTML로 변환했습니다.
하지만 Custom Blot을 사용했기 때문에 기본 변환만으로는 부족했고, 추가 작업이 필요했습니다.
const delta = JSON.parse(post.content);
const converter = new QuillDeltaToHtmlConverter(delta.ops);
converter.renderCustomWith((customOp) => {
if (customOp.insert.type === 'customImage') {
const { id, url } = customOp.insert.value;
return `<img src="${url}" data-id="${id}" />`;
}
return '';
});
const html = converter.convert();
return <div dangerouslySetInnerHTML={{ __html: html }} />;
이처럼 renderCustomWith
를 사용해 customImage
를 <img src="..." data-id="...">
형태로 직접 변환하도록 처리했습니다.
Custom Blot을 이용해 이미지의 url
과 id
를 함께 관리할 수 있게 되었고, 최종 제출 시 올바른 ID 값을 서버에 전달하여 백엔드에서 이미지를 효율적으로 관리할 수 있게 되었습니다.
또한 Delta
→ HTML
변환 과정에서도 Custom Blot을 대응하도록 구현해, 이미지가 <img src="..." data-id="...">
형태로 정상적으로 렌더링되도록 처리했습니다.