웹 에디터 (React-quill)

huni_·2022년 7월 7일
16

React 설치

목록 보기
12/16

게시물을 등록하는 게시물 등록 페이지를 만든다고 했을 때,

글을 작성한 작성자와 글에 대한 내용을 담는 부분을 만든다면

아래의 방법을 이용해서 만들어 본 적이 있으신가요?

내용을 담아오는 페이지를 구성할 때는

input 태그textarea 태그를 이용해 내용을 담아올 수 있습니다.

그런데, textarea 태그에서 줄바꿈으로 내용을 입력하고 글을 등록했을 때

가져온 데이터를 보면 아래의 결과가 나타납니다.

"어? 나는 줄바꿈을 했는데? 왜 한 줄로 붙여나오지?"

라는 생각이 드는 타이밍이죠?

textarea 태그의 특성상, 내용을 입력할 때 직접 줄바꿈을 주었더라도

내용 데이터를 출력할 때에 줄바꿈에 대한 결과를 따로 처리해주지 않으면

한 줄로 내용을 출력하게 됩니다.

그 외에도 내용 중에서 더 중요한 부분을 표시하고 싶다거나

폰트에 색깔을 추가하고 싶다거나 하는 등의 스타일 부분이 필요할 수도 있습니다.

이러한 단점들을 보완해서 좀더 스타일리쉬한 내용을 작성할 수 있도록 도와주는

'React-Quill' 라이브러리를 적용해보도록 하겠습니다.

📖 React-Quill Docs 페이지

1. 웹 에디터 적용하기

먼저, 터미널을 실행한 후

yarn add react-quill 명령어로 React-Quill 을 설치합니다.


yarn add react-quill
npm install react-quill

설치가 완료되었다면,

웹 에디터를 추가하고 싶은 페이지의 최상단에서

React-Quill을 호출해줘야 합니다.

import ReactQuill from 'react-quill';
import 'react-quill/dist/quill.snow.css';

React-Quill에서 사용될 스타일 CSS 파일까지 함께 호출해서

스타일도 함께 적용해주겠습니다.

라이브러리를 호출했다면,

웹 에디터를 사용하고 싶은 부분에

처럼 사용해서 사용할 수 있게 됩니다.

자, 여기까지 적용됐다면

이제 프로젝트에 웹 에디터를 사용할 수 있게 되었습니다.

프로젝트 페이지에서 한번 새로고침을 해보세요!

잘 작동하시나요?!

혹시 이런 에러 페이지가 뜨지 않으신가요?

Next JS 프로젝트를 사용하고 계시다면

정상으로 뜨는 에러입니다.

Next JS 는 기본적으로 서버사이드 렌더링을 지원하게 되는데

서버로부터 웹 페이지를 렌더링하는 시점에서는

window 또는 document object를 선언하기 전이기 때문에

document가 선언되지 않았다는 에러가 발생하게 됩니다.

이 문제를 해결하기 위해서는

React-Quillimport 하게 되는 시점을

document 가 선언된 시점 이후에 선언할 수 있게 해야합니다.

이때 사용할 수 있는 방법으로는

next jsdynamic import 방식을 사용할 수 있습니다.

기존의 코드 대신에

아래의 코드를 새로 추가해주세요.

import dynamic from 'next/dynamic';

const ReactQuill = dynamic( () => import('react-quill'), {
    ssr : false
})

dynamic은, 해당 모듈을 호출하는 시점을

document에 대한 정보가 선언된 후의 시점으로 옮겨서

호출을 할 수 있게 도와줍니다.

이때 사용할 수 있는 방법으로는

next jsdynamic import 방식을 사용할 수 있습니다.

기존의 코드 대신에

아래의 코드를 새로 추가해주세요.

import dynamic from 'next/dynamic';

const ReactQuill = dynamic( () => import('react-quill'), {
    ssr : false
})

dynamic은, 해당 모듈을 호출하는 시점을

document에 대한 정보가 선언된 후의 시점으로 옮겨서

호출을 할 수 있게 도와줍니다.

즉, 빌드되는 시점에서 호출하는 게 아닌

런타임 시점에서 모듈을 호출을 해서

이미 documnet가 선언되어 있는 시점의 환경을

제공해줄 수 있습니다.

그럼 이번에는

웹 에디터가 잘 적용되었는지 확인해볼까요?

이번에는 에러 없이 웹 에디터가 잘 적용된 결과를

확인할 수 있습니다.

마지막으로 웹 에디터에 작성한 내용들을

가져와보는 과정을 알아볼까요?

Quill 라이브러리를 호출하는 컴포넌트에

onChange 을 사용할 수 있습니다.

onChange 함수로 내용이 변경될 때마다 실행되는 함수를 만들어주는데

함수에서는 첫번째 인자로 입력되는 내용들을 가져올 수 있습니다.

❗ contents 인자는 예시입니다.

인자는 변수처럼 자유롭게 이름을 붙여주셔도 됩니다!

해당 인자를 console.log로 출력해보면

오른쪽과 같이 HTML 태그들로 이루어진 문자열 데이터로 들어오게 됩니다.

이전에서는 textarea로 줄바꿈이 되지 않았던 부분을

<p> 태그로 묶어지면서 자동으로 줄바꿈이 될 수 있는 환경을 제공해주게 됩니다.

💯 도전 ::

contents 이름을 가지는 State 를 생성한 후에
웹 에디터에 입력된 내용들을 저장해보세요!

자, 이제 입력된 웹 에디터 내용을

화면에 출력해보려고 합니다.

웹 에디터로 입력된 내용은 HTML 태그로 묶여서 입력이 되기 때문에

실제로는 HTML 태그들을 노출시키지 않는 상태에서 HTML 기능이 적용될 수 있도록

화면에 출력해야 합니다.

그런데, 우리가 사용하고 있는 React 프로젝트에서는

기본적으로 HTML 보안 이슈로 인해 HTML 태그를 직접 삽입 할 수 없게 설정되어 있습니다.

HTML 태그를 사용하고자 한다면

아래의 코드로 HTML 태그를 삽입 할 수 있습니다.

<div dangerouslySetInnerHTML={{ __html :  HTML 태그 추가  }} />

dangerouslySetInnerHTML

div 또는 span 태그에서 제공되는 속성인데

"당신은 프로젝트에 HTML 태그를 추가하려는 행위가 위험하다는 걸 알고 있다.
그럼에도 HTML 태그를 추가하고 싶다면 추가하려는 HTML 태그를 작성해라."

라는 의미로,

위험성을 감수하고 HTML 태그를 추가할 때 사용하는 속성이며

안쪽으로는 __html 속성 값에 추가하려는 데이터를 입력해주면 됩니다.

div 및 span 태그dangerouslySetInnerHTML 를 사용한다면
반드시 빈 태그 형식으로 작성해주셔야 합니다.

자, 이제 웹 에디터로 작성된 내용들이

제대로 웹 페이지에 출력이 되는지 확인해보겠습니다.

위와 같은 구조로 웹 에디터로 입력된 HTML 데이터를

dangerouslySetInnerHTML속성을 이용해 div 태그에 입력해주면

웹 페이지로 HTML 태그들이 적용된 결과들이 출력되는 것을 확인할 수 있습니다.


크로스 사이드 스크립트

React - quill을 실습하며 발생하는 위험성에 대해서 알아봤습니다.

예시로 들었던 스크립트를 활용한 토큰 탈취 처럼 취약점을 노려서 javascriptHTML로 악의적 코드를 웹 브라우저에 심어, 사용자 접속시 그 악성코드가 실행되는 것을 크로스 사이드 스크립트 라고 합니다.

이 문제에 대한 방어법중 하나는 dompurify 입니다.

yarn add dompurify
yarn add -D @types/dompurify

코드에 적용시켜 안정성을 확보할 시간입니다!

하지만 지금은 발생하지 않지만 이렇게 작성해을 주면 Hydration Issue가 생깁니다.

여기서 하이드레이션은 렌더링 결과물의 컴포넌트를 확인하고 각 컴포넌트의 이벤트들을 실제 DOM에 걸어주는데, 이 경우 SSR시 렌더링되는 컴포넌트와 CSR시 렌더링되는 컴포넌트가 있기에 DOM에서 읽어주는 순서가 꼬이게 되어버린다. 이를 방지하기위해 SSR / CSR 렌더링 컴포넌트를 동일하기 주기 위해 빈 값을 넣어주어 해결해 줍니다.


OWASP TOP 10

위에서 알아본 크로스 사이드 스크립트처럼 웹에는 여러 공격들이 있고, 그 만큼 사람들은 보안에 신경을 많이 쓰게 되었습니다.

OWASPOpen Web Application Security Project의 약자로 오픈소스 웹 애플리케이션 보안 프로젝트입니다.

주로, 웹 관련 정보노출이나 악성파일 및 스크립트, 보안 취약점을 연구하며 10대 취약점을 발표합니다.

매년 탑 1을 유지하는 것이 Injection입니다.

SQL쿼리문을 작성할 때 조건을 통해 데이터를 주고 받는데, 이 조건을 직접 조작하여 공격합니다. 이를 현재는 ORM을 사용해 막고 있습니다.

그 외 여러 공격들이 있는데, 이는 OWASP 발표에서 확인 할 수 있습니다.


2. React-Quill Custom

웹 에디터를 추가하기는 했는데,

제공하는 기능도 별로 없고 에디터라기에는 횡 한 느낌이 드시죠?

현재까지는 React-Quill에서 기본적으로 제공하는 기능들만 사용할 수 있는데

내가 원하는 기능들로 웹 에디터를 커스텀 할 수도 있습니다.

먼저, React-Quill에서 modules 라는 속성으로

웹 에디터에서 사용할 기능들을 추가해줄 수 있습니다.

📖 React-quill Docs 참고

웹 에디터가 추가되어있는 페이지에 modules 상수를 생성한 후

웹 에디터 기능에 추가할 요소들을 새로 넣어줍니다.

const modules = {
    toolbar: {
        container: [
          [{ 'header': [1, 2, 3, 4, 5, 6, false] }],
          [{ 'font': [] }],
          [{ 'align': [] }],
          ['bold', 'italic', 'underline', 'strike', 'blockquote'],
          [{ 'list': 'ordered' }, { 'list': 'bullet' }, 'link'],
          [{ 'color': ['#000000', '#e60000', '#ff9900', '#ffff00', '#008a00', '#0066cc', '#9933ff', '#ffffff', '#facccc', '#ffebcc', '#ffffcc', '#cce8cc', '#cce0f5', '#ebd6ff', '#bbbbbb', '#f06666', '#ffc266', '#ffff66', '#66b966', '#66a3e0', '#c285ff', '#888888', '#a10000', '#b26b00', '#b2b200', '#006100', '#0047b2', '#6b24b2', '#444444', '#5c0000', '#663d00', '#666600', '#003700', '#002966', '#3d1466', 'custom-color'] }, { 'background': [] }],
          ['image', 'video'],
          ['clean']  
        ],
    }
}

간략하게 해석하자면, toolbar 는 웹 에디터에서 기능들을 담을 수 있는데

이 toolbar 의 container 안으로 배열 형태로 추가해주거나 제거해서

사용할 기능들을 커스텀 할 수가 있습니다.

위의 코드를 추가하게 된다면

기존의 웹 에디터 툴바에 폰트 색상, 폰트 배경색상, 이미지 추가, 비디오 추가 등등의

여러 기능들이 새로 생기게 됩니다.

다음으로, 추가한 modules 객체 데이터를

React-Quill을 호출하는 컴포넌트에 modules 의 속성으로 설정해줘야 합니다.

자, 여기까지 저장이 됐다면

다시 웹 에디터를 확인해볼까요?

이전과 달리 못 보던 아이콘들이 생긴 것을 확인할 수 있으신가요?

표시된 아이콘들은 방금, modules 객체에서 toolbarcontainer로 추가된 기능들이

웹 에디터에 적용되어 사용할 수 있게 된 것들입니다.

💯

도전 1 ::
toolbar 의 기능 아이콘들의 위치를 변경해보세요.
도전 2 ::
폰트 색상을 5개 이상 추가해보세요.

여기까지가 프로젝트에 웹 에디터인 React-Quill 라이브러리 적용 방법입니다.

웹 에디터는 React-Quill 을 제외하고도 CKEditor-5, Wysiwyg 등이 있으니

여러가지 에디터를 적용해보시는 걸 추천드리겠습니다 😇

profile
FrontEnd Developer

0개의 댓글