Toast UI Editor (TUI Editor) 에서 이미지 업로드시 base64 문자열 제거하기

Front-end/React.js

Toast UI Editor (TUI Editor) 에서 이미지 업로드시 base64 문자열 제거하기

조커린 2021. 6. 29. 13:32

Toast UI Editor는 이미지 업로드 시 이미지가 base64의 형태로 자동 변환되어 업로드된다.
base64는 엄청 긴 문자열이기 때문에 이를 데이터 베이스에 업로드시 여러분의 데이터 베이스는 살아남지 못할 것
그래서 이미지 업로드시 콜백 함수로 서버의 어떤 위치에 저장을 한 후에 해당 사진의 url을 리턴 값으로 받아서 에디터에 출력시켜주어야 한다.
TUI Editor가 요즘 뜨는 신흥강자라고 해서 나도 이번 프로젝트에 적용하며 사용해보다가
저 부분을 개선하기 위해 인터넷을 서칭해보고
addImageBlobHook을 이용하면 된다는 걸 보고 적용하려 했는데
base64랑 url이 두 개 다 삽입이 되는 것이다...ㅠㅠㅠㅠ
개선하기 위해 해당 깃 헙의 이슈를 뒤졌는데 해결한 분이 있긴 했다.
https://github.com/nhn/tui.editor/issues/1588

 

addImageBlobHook inserts image twice (once as base64 and custom) · Issue #1588 · nhn/tui.editor

Describe the bug Thanks for the great work on the latest upgrade! The addImageBlobHook does not work anymore as expected since upgrading to 3.0.0. I couldn't find anything about it in the migra...

github.com

removeHook을 이용해서 디폴트 함수를 제거한 후에 다시 세팅을 해야 하는데 아무리 뒤져봐도 잘 안 보이고 감이 안 오는 것...
근데 그냥 공식문서에 있었다 ㅠㅠㅠ
리액트 카톡방에 올려서 선배님께 답변을 받아 잘 적용했다... 바보 같은 나 ㅠㅠㅠ

감사합니다...

적용 코드!

editorRef가 컴포넌트에 떠야 해당 인스턴스를 제어할 수 있으니 useEffect를 이용

import React, { useRef, useEffect } from "react";
import "@toast-ui/editor/dist/toastui-editor.css";
import { Editor } from "@toast-ui/react-editor";
import axios from "axios";
import { backUrl } from "../../config/config";

const TextEditor = ({ setText }) => {
  const editorRef = useRef();
  useEffect(() => {
    if (editorRef.current) {
      editorRef.current.getInstance().removeHook("addImageBlobHook");
      editorRef.current
        .getInstance()
        .addHook("addImageBlobHook", (blob, callback) => {
          (async () => {
            let formData = new FormData();
            formData.append("file", blob);

            axios.defaults.withCredentials = true;
            const { data: url } = await axios.post(
              `${backUrl}image.do`,
              formData,
              {
                header: { "content-type": "multipart/formdata" },
              }
            );
            callback(url, "alt text");
          })();

          return false;
        });
    }

    return () => {};
  }, [editorRef]);

  return (
    <div>
      <Editor
        usageStatistics={false}
        initialValue="스터디에 대한 정보를 간략히 작성해주세요 '-'"
        previewStyle="tab"
        height="600px"
        initialEditType="wysiwyg"
        useCommandShortcut={true}
        onChange={() => {
          const innerTxt = editorRef.current.getInstance().getMarkdown();
          setText(innerTxt);
        }}
        ref={editorRef}
      />
    </div>
  );
};

export default TextEditor;


---------- 내용 추가

🥸 Vue용 TUI Editor


지금 버전의 에디터 소스코드가 어떻게 달라졌는 지는 모르겠지만, 최근 글을 찾아보니 addHook 호출 시 기존에 있는 이벤트를 제거하고 해당 함수를 덮어준다고 합니다.
일단 Editor에 ref로 해당 객체를 가지고 올 수 있게 하는 점은 동일한데, 인스턴스를 어떻게 가지고 오는 지와, addHook만 호출해도 됐던 점이 리액트 버전과 다른 점 인 것 같아요.
외부 비동기 호출하는 것은 위와 유사하게 하시면 될 것 같아요.
imageURL은 dogg 이라고 쳤는데 스눕독 나오길래 그대로 갖다 썼는데;;(놀라지마세요..),
axios로 업로드하고 해당 URL받아서 처리하는 부분은 동일하니 그렇게 하시면 될 것 같습니다.

<template>
  <div>
    <editor
        ref="toastEditor" 
        :options="editorOptions"
    />
  </div>

</template>

<script>
import '@toast-ui/editor/dist/toastui-editor.css';
import { Editor } from '@toast-ui/vue-editor';

export default {
  components: {
    editor: Editor
  },
  data() {
    return {
      editorOptions: {
        usageStatistics: false,
      },
    };
  },
  mounted() {
    console.log(this.$refs.toastEditor)

    const instance = this.$refs.toastEditor
    const imageURL= "https://www.biography.com/.image/ar_16:9%2Cc_fill%2Ccs_srgb%2Cfl_progressive%2Cq_auto:good%2Cw_1200/MTQ3NjM5ODIyNjU0MTIxMDM0/snoop_dogg_photo_by_estevan_oriol_archive_photos_getty_455616412.jpg"

    instance.invoke("addHook", "addImageBlobHook", function(
        file,
        callback
    ) {
      const el = instance.$el;
      console.log(el)
      console.log(file)
      callback(imageURL)
    });
  }
};
</script>

 

Thymeleaf 템플릿용 추가 (npm이 아닌 cdn 방식에서 활용하기)

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" type="text/css" href="https://uicdn.toast.com/editor/latest/toastui-editor.min.css" />
</head>
<body>

<div id="editor"></div>
<script th:src="@{https://uicdn.toast.com/editor/latest/toastui-editor-all.min.js}"></script>
<script>
    const Editor = toastui.Editor;

    const editor = new Editor({
        el: document.querySelector('#editor'),
        height: '600px',
        initialEditType: 'markdown',
        previewStyle: 'vertical',

    });
    editor.addHook("addImageBlobHook", function(blob, callback){
        // blob 텍스트 
        console.log(blob)
        
        // !!!!! 여기서 이미지를 받아와서 이미지 주소를 받아오고 (ajax 등으로)
        // callback의 인수로 넣으시면 됩니다. 
        callback("콜백으로 받아온 이미지 URL")
    })
    // 텍스트 가지고 오기 
    console.log(editor.getMarkdown())
</script>
</body>
</html>






올리는 건 별로 없지만...
블로그 관리는 계속 할 예정입니다 ㅠ_ㅜ
이 글로 유입되는 분들이 많으신데 댓글 많이 달아주세요...ㅎㅎ
궁금한 점이 있으시다면 제가 할 수 있는 선에서 최대한 도움 드리겠습니다 :0


 

위의 소스를 깃허브에 올려두었어요

 

https://gareen.tistory.com/92

 

Toast UI Editor 이미지 업로드 샘플들 (React.js/Vue.js/Thymeleaf)

Toast UI Editor 이미지 업로드 샘플들을 깃허브 레파지토리에 올렸습니다. 올라온 질문들 구현소스도 있고, 깃허브로 공유하는 게 나을 것 같아서요. (그런데 버전 문제가 좀 있더라고요. 리액트버

gareen.tistory.com

혹시 길 잃으시거나 잘 모르시겠는 분들은 위의 포스팅(깃허브) 참고해주세요