[React + TypeScript] + Tiptap editor로 에디터 만들기

LEEJAEJUN·2023년 11월 11일
0

fasttime

목록 보기
3/3
post-thumbnail

✨ Tiptap 채택 이유

사실 이러면⬆︎ 안 된다는 것쯤은 알지만... Rich Text Editor라는 이름 자체를 처음 들어봐서 무엇을 왜 써야하는지 명확한 이유를 찾는 나만의 기준이 없었기에. 그래도 최소한의 방어선이 있었는데, 아래와 같았다.

  • 유명할 것
  • 다양한 곳에서 채택할 것
  • 참고할 글이나 영상이 충분할 것

인프런에서 사용하고, 유튜브나 블로그 글도 꽤 많고, 다양한 기능이 있고, LogRocket에서도 추천하는~ 뭐 여튼 이런 이유로 채택하게 되었다.

✨ 결과물

✨ 사용하면서 겪은 어려움

🔥 본문을 서버에 전송할 수 있게 string으로 바꾸고, title과 content로 분리하는 작업

// request body type
title: string;
content: string;

// 본문을 title과 block으로 나누기
const DocumentWithTitle = Document.extend({
  content: 'title block+',
});

// title 노드 생성
const Title = Node.create<TitleProps>({
  name: 'title',

  addOptions() {
    return {
      level: 1,
      HTMLAttributes: {},
    };
  },

  content: 'text*',

  marks: '',

  group: 'block',

  defining: true,

  renderHTML({ HTMLAttributes }) {
    const level = this.options.level;

    return [`h${level}`, mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
  },
});
// h1 선택 (title)
const titleNode = doc.querySelector('h1');
// 제목 없으면 에러
if (!titleNode || !titleNode.textContent) {
  alert('제목을 입력해주세요');
  return;
}
// 본문에서 제목 제거
titleNode.remove();
// 실제 content
const updatedHTML = doc.body.innerHTML;

🔥 발행 시 이미지를 firebase에 업로드 하면서 그 URL을 이미지 src로 대체하는 작업

// text를 html로 변환
const doc = parser.parseFromString(articleHTML, 'text/html');
// 모든 img 태그 선택
const images = doc.querySelectorAll('img');
// 이미지를 firebase에 업로드 후 src를 그 URL로 변환
const uploadImageAndChangeURL = Array.from(images).map(async (image) => {
  const blobUrl = image.src;
  const blob = await createBlob(blobUrl);
  const downloadUrl = await uploadImageToFirebase(blob);

  image.src = downloadUrl;
});
// 모든 img 작업이 끝날 때까지 대기
await Promise.all(uploadImageAndChangeURL);

🔥 메뉴바 코드 간결하게 수정

  • 반복되는 코드가 많아서 하나의 컴포넌트로 묶고 싶었는데, 계속 에러가 나고 시간도 촉박해서 실패

🔥 에디터 디자인

  • 에디터 높이를 뷰포트와 동일하게 가져가고 스크롤은 글 본문 내부에서만 생기도록 제작

🔥 게시글 작성, 수정 에디터 나누기

  • 에디터에 mode Props를 받게 설정해서 모드에 따라 버튼과 그 버튼의 로직이 바뀌게 제작

✨ 좋은 점

➕ 문서 예시 코드가 친절하다.
➕ 다양한 익스텐션이 있다. (함께 쓰기, 이미지 등)
➕ 커스텀하기 좋다.

✨ 아쉬운 점

➖ 학습양이 꽤 방대하다.
➖ 타입스크립트랑 쓰기가 힘들다.
➖ 코드를 분리하기가 어렵다. (이건 내 리액트 실력 문제일 가능성이 크긴 하다)
➖ css module로 사용하는 방법이 없다(?)
➖ 아직 이런저런 버그가 많다.

profile
always be fresh

0개의 댓글