NextJsProseMirrorShiki

[ Introduction > Blog ]

[๋ธ”๋กœ๊ทธ ์†Œ๊ฐœ] ํ”„๋ก ํŠธ์—”๋“œ - ์—๋””ํ„ฐ

ย Carrot Yoon
ย 2025-03-16
ย 276

๋ธ”๋กœ๊ทธ ์†Œ๊ฐœ โ€“ ์—๋””ํ„ฐ

์•ˆ๋…•ํ•˜์„ธ์š”. ์ฒซ ๋ฒˆ์งธ ๋ธ”๋กœ๊ทธ ๊ธ€์ž…๋‹ˆ๋‹ค.
์ €๋Š” ํ”„๋กœ๊ทธ๋ž˜๋ฐํ•˜๋ฉด์„œ ๊ณ ๋ฏผํ•˜๊ณ  ํ•ด๊ฒฐํ•œ ๊ณผ์ •์„ ๊ธฐ๋กํ•˜๊ณ  ๊ณต์œ ํ•˜๊ธฐ ์œ„ํ•ด ๋ธ”๋กœ๊ทธ๋ฅผ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค. ๊ธ€์„ ์ž˜ ์“ฐ๋Š” ํŽธ์€ ์•„๋‹ˆ์ง€๋งŒ, ์ˆ˜์ •ยท๋ณด์™„ํ•˜๋ฉด์„œ ํšจ์œจ์ ์œผ๋กœ ์ง€์‹์„ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๋„๋ก ํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

์ด๋ฒˆ ๊ธ€์—์„œ๋Š” ์ œ๊ฐ€ ์ง์ ‘ ๋งŒ๋“  ๋ธ”๋กœ๊ทธ ์—๋””ํ„ฐ๋ฅผ ์†Œ๊ฐœํ•˜๋ ค ํ•ฉ๋‹ˆ๋‹ค.
1๋‹ฌ ๊ฐ€๊นŒ์ด ๋‹ค์–‘ํ•œ ์—๋””ํ„ฐ๋ฅผ ํ…Œ์ŠคํŠธํ–ˆ๊ณ , ๊ฒฐ๊ตญ ProseMirror ๊ธฐ๋ฐ˜ Tiptap์„ ์„ ํƒํ–ˆ์Šต๋‹ˆ๋‹ค.

ํŒํƒญ์€

  • ํ™•์žฅ์„ฑ์ด ๋›ฐ์–ด๋‚˜๊ณ 

  • Viewer๋ฅผ JSON/Text ํ˜•์‹ ๋ชจ๋‘ SSR ๊ฐ€๋Šฅ

  • Next.js & ๋ฐฑ์—”๋“œ์™€ ๊ถํ•ฉ์ด ์ข‹์Œ

์—๋””ํ„ฐ

SSR

ํ™•์žฅ์„ฑ

์—”์ง„

WYSIWYG

Markdown

RIch Text

๊ธฐํƒ€

editor.js

๐ŸŸก

โ†—๏ธ

์ž์ฒด

โœ…

๐ŸŸก

โœ…

๋ฌธ์„œ ์ข‹์Œ. Json ๊ตฌ์กฐ.

react-md-editor

โŒ

โžก๏ธ

์ž์ฒด

โŒ

โœ…

โŒ

์ด์ง€์œ… ์‚ฌ์šฉ์„ฑ ์•ˆ์ข‹์Œ.

toast UI

โŒ

โฌ‡๏ธ

ProseMirror

โœ…

โœ…

โœ…

๋ฌธ์„œํ™” ๋‚˜์จ. ํ”Œ๋Ÿฌ๊ทธ์ธ ์ ์Œ.

quill

๐ŸŸก

โ†—๏ธ

Delta

โœ…

๐ŸŸก

โœ…

๋ฌธ์„œ ์ข‹์Œ. JSON ๊ตฌ์กฐ.

TipTap

โœ…

โ†—๏ธ

ProseMirror

โœ…

๐ŸŸก

โœ…

๋ฌธ์„œ ๋ณดํ†ต. ๊ธฐ๋Šฅ ์ž˜ ๋‚˜๋‰จ.

ProseMirror

โœ…

โฌ†๏ธ

์ž์ฒด

โœ…

โŒ

๐ŸŸก

๋ฌธ์„œ ์ตœ๊ณ . ๋†’์€ ๋Ÿฌ๋‹ ์ปค๋ธŒ.

๐Ÿ‘‰ ๊ฒฐ๋ก : ๊ฐ„๋‹จ ๊ธฐ๋Šฅ ์œ„์ฃผ๋ผ๋ฉด Quill/Editor.js ์ถ”์ฒœ. ํ•˜์ง€๋งŒ ์ปค์Šคํ…€ ๊ธฐ๋Šฅ ๋งŽ์ด ํ•„์š”ํ•˜๋‹ค๋ฉด Tiptap/ProseMirror๊ฐ€ ์ตœ์ ์ผ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

1. ๊ธฐ๋Šฅ ์ •์˜

์ €์˜ ์—๋””ํ„ฐ์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ๋“ค์˜ ๊ธฐ๋Šฅ๋“ค์„ ์ •๋ฆฌํ•ด ๋ดค์Šต๋‹ˆ๋‹ค.

  1. ๊ธฐ๋ณธ ํ…์ŠคํŠธ ํŽธ์ง‘ ๊ธฐ๋Šฅ

    • ๊ธ€์”จ์ฒด ๋ณ€๊ฒฝ (๊ตต๊ฒŒ, ๋ฐ‘์ค„, ๊ธฐ์šธ์ž„, ์ƒ‰๊น”, ๋ฐฐ๊ฒฝ์ƒ‰)

    • ๊ธ€๋จธ๋ฆฌ ๊ธฐํ˜ธ, ๋ฒˆํ˜ธ ๊ธฐํ˜ธ, ์ฒดํฌ ๋ฆฌ์ŠคํŠธ

    • ๋ฌธ๋‹จ ์ขŒ, ์šฐ, ๊ฐ€์šด๋ฐ ์ •๋ ฌ

    • ๋งˆํฌ๋‹ค์šด ๋ฌธ๋ฒ• ์ง€์› (#์ ๊ณ  ๋„์šฐ๋ฉด h1 ํƒœ๊ทธ.. ```js ์ž‘์„ฑ์‹œ js ์ฝ”๋“œ ๋ธ”๋ก ์ž๋™ ์ƒ์„ฑ)

    • ๋“ค์—ฌ์“ฐ๊ธฐ, ๋‚ด์–ด์“ฐ๊ธฐ

    • ํ•˜์ดํผ ํ…์ŠคํŠธ ์ƒ์„ฑ

  2. Viewer์˜ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง

    • Viewer๋Š” ์„œ๋ฒ„์‚ฌ์ด๋“œ ๋ Œ๋”๋ง(SSR)์ด ๊ฐ€๋Šฅํ•˜์—ฌ NextJs์˜ ISR, SSG๋กœ ์บ์‹ฑ๊ฐ€๋Šฅ

  3. ์ฝ”๋“œ ๋ธ”๋ก ๋ฐ ์ฝ”๋“œ ํ•˜์ด๋ผ์ดํŒ…

    • ์ฝ”๋“œ ๋ธ”๋ก์— ์„ค์ •ํ•œ ์ฝ”๋”ฉ ์–ธ์–ด์— ๋งž๋Š” ๋ฌธ๋ฒ• ๊ฐ•์กฐ

    • Code Syntax Highlighter๋Š” SSR์ด ๊ฐ€๋Šฅํ•˜์—ฌ, NextJs์˜ ISR, SSG๋กœ ์บ์‹ฑ๊ฐ€๋Šฅ.

    • ๊ธฐ๋ณธ Syntax Highlighted๋œ ์ฝ”๋“œ์— ์„œ์‹ ์ถ”๊ฐ€.(ํ˜•๊ด‘ํŒฌ, ๋ฐ‘์ค„ ๋“ฑ)

    • VS Code์—์„œ ๋ณต์‚ฌํ•œ ์ฝ”๋“œ๋Š” ์ž๋™์œผ๋กœ ํ•ด๋‹น ํŒŒ์ผ์˜ ์–ธ์–ด๋ฅผ ๊ฐ์ง€ํ•˜์—ฌ ์ฝ”๋“œ ๋ธ”๋ก ์ƒ์„ฑ

  4. ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ ๋ฐ ๊ด€๋ฆฌ

    • ์ด๋ฏธ์ง€ ์ •๋ ฌ ๋ฐ ํฌ๊ธฐ ์กฐ์ • ๊ธฐ๋Šฅ ์ง€์›

    • ๋ณต์‚ฌ-๋ถ™์—ฌ๋„ฃ๊ธฐ ์‹œ ํŽธํ•˜๊ฒŒ S3์— ์—…๋กœ๋“œํ•˜์—ฌ URL์„ ๋ฐ›์•„ ์‚ฌ์šฉ

    • ์—…๋กœ๋“œ ์‹œ, WebP ์••์ถ• ํ›„ ๋น„๊ตํ•˜์—ฌ ํšจ์œจ์ ์ธ ํฌ๋ฉง ์‚ฌ์šฉ.

    • ๊ธฐ์กด์˜ ์ด๋ฏธ์ง€ URL์„ ์žฌํ™œ์šฉํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œ ์—…๋กœ๋“œ ๋ฐฉ์ง€.

  5. ๋ชฉ์ฐจ(TOC) ์ž๋™ ์ƒ์„ฑ

    • ํ—ค๋”๋ฅผ ํ†ตํ•ด ์ž๋™์œผ๋กœ ๋ชฉ์ฐจ(TOC) ์ƒ์„ฑ

  6. ์ฒซ ์Šฌ๋ž˜์‰ฌ, ๋“œ๋ž˜๊ทธ ์ž๋™์™„์„ฑ

    • "/"๋ฅผ ์ž…๋ ฅํ•˜๋ฉด ์ฃผ์š” ๊ธฐ๋Šฅ๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

    • ๋‚ด์šฉ์„ ๋“œ๋ž˜๊ทธํ•˜๋ฉด ๋“œ๋ž˜๊ทธํ•œ ์˜์—ญ์— ํ•„์š”ํ•œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ๊ธฐ๋Šฅ ์†Œ๊ฐœ

6๊ฐ€์ง€ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ์–ด๋ ค์› ๋˜ ์  ๋ฐ ๊ตฌํ˜„ ๋ฐฉ๋ฒ•์„ ๊ฐ„๋‹จํžˆ ์†Œ๊ฐœํ•˜๊ฒ ์Šต๋‹ˆ๋‹ค.

2.1 Code Syntax Highlighter

  • ๊ฐœ๋ฐœ ์ด์œ : ๊ฐœ๋ฐœ ๋ธ”๋กœ๊ทธ๋ผ ๋‹ค์–‘ํ•œ ์–ธ์–ด ์ฝ”๋“œ ๊ฐ•์กฐ๊ฐ€ ํ•„์ˆ˜

  • ๊ตฌํ˜„: Shiki ๊ธฐ๋ฐ˜, 100+ ์–ธ์–ด ์ง€์›, Line ๋‹จ์œ„ ํŒŒ์‹ฑ โ†’ Line number ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅ

  • ํŠน์ง•: ์ฝ”๋“œ ๋ธ”๋ก์— ํ˜•๊ด‘ํŽœยท๋ฐ‘์ค„ยท์ทจ์†Œ์„  ๊ฐ™์€ ๋งˆํฌ๋„ ์ ์šฉ ๊ฐ€๋Šฅ. VS Code ๋ณต๋ถ™ ์–ธ์–ด ์ž๋™ ๊ฐ์ง€.

  • ์–ด๋ ค์›€: ProseMirror Schema/Mark ์ถฉ๋Œ ํ•ด๊ฒฐ โ†’ 2์ฃผ ์ด์ƒ ์†Œ์š”

์„ฑ๊ณผ: ์—๋””ํ„ฐ์™€ ํ•œ ๋ชธ์ฒ˜๋Ÿผ ์ž‘๋™(์—๋””ํ„ฐ ์ปจํ…์ŠคํŠธ ์—ฐ๋™), ๋ฐ์ดํ„ฐ ์ด์ค‘ ์ €์žฅ ๋ถˆํ•„์š”

image.webp

2.2 Viewer์˜ ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง

  • ๊ฐœ๋ฐœ ์ด์œ : Next.js ISR/SSG ์บ์‹ฑ์„ ํ†ตํ•œ ๋น ๋ฅธ ๋ Œ๋”๋ง

  • ๊ณ ์•ˆํ•œ ๋ฐฉ์‹๋“ค :

    1. ํด๋ผ์ด์–ธํŠธ์—์„œ HTML ์ „๋‹ฌ โ†’ ๋ณด์•ˆ ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ์Œ.

    2. ์„œ๋ฒ„์—์„œ SSR๋กœ ๋ฐ์ดํ„ฐ ํŒŒ์‹ฑ๊ณผ Sanitizing ์ˆ˜ํ–‰ โ†’ ์ตœ์‹  ๋ฐ˜์˜, ์•ˆ์ „

  • ๊ตฌํ˜„ : ์„œ๋ฒ„์—์„œ ๋ฐ์ดํ„ฐ ์ €์žฅ + ํŒŒ์‹ฑํ•œ HTML ์บ์‹ฑ ๋ณ‘ํ–‰ โ†’ ๋น ๋ฅด๊ฒŒ ์ถœ๋ ฅ ๋ฐ ์•ˆ์ „

  • ์žฅ์ : ๋ณด์•ˆ ๊ฐ•ํ™”, ๋ฐ์ดํ„ฐ ์ค‘๋ณต ์ €์žฅ ๋ถˆํ•„์š”

2.3 ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ

article_img
  • ๊ฐœ๋ฐœ ์ด์œ  : S3 ์ €์žฅ์†Œ์— ์‹ค์‹œ๊ฐ„ ์ด๋ฏธ์ง€ ์—…๋กœ๋“œ๊ฐ€ ํ•„์š”.

  • ๊ตฌํ˜„ : ํด๋ฆฝ๋ณด๋“œ ๋ถ™์—ฌ๋„ฃ๊ธฐ โ†’ WebP ์••์ถ• โ†’ S3 ์—…๋กœ๋“œ ํ›„ URL ๋ฐ˜ํ™˜

  • ์–ด๋ ค์›€ : ์™ธ๋ถ€ URL ์ฒ˜๋ฆฌ ๋ฐฉ์•ˆ๊ณผ CSP ์„ค์ •์— ๋Œ€ํ•œ ๊ณ ๋ฏผ

  • ์žฅ์  : ๊ธฐ์กด URL ์žฌํ™œ์šฉ โ†’ ์ค‘๋ณต ์—…๋กœ๋“œ ๋ฐฉ์ง€

2.4 ๊ธฐ๋ณธ ํ…์ŠคํŠธ ํŽธ์ง‘ ๊ธฐ๋Šฅ

image.webp

image.webp

  • ๊ตฌํ˜„ : Tiptap์— ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ํ˜•์‹์— ๋งž๊ฒŒ ๊ฐœ๋ฐœ

  • ์–ด๋ ค์›€ : ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๋ ค๋ฉด ProseMirror ๋ฌธ์„œ๊นŒ์ง€ ์ฐธ๊ณ ํ•ด์•ผ ํ•จ.

  • ์žฅ์  : ์–ธ์ œ๋“  ๊พธ๋ฏธ๋Š” ์ž์œ ๋„๋ฅผ ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋กœ ํ™•์žฅํ•  ์ˆ˜ ์žˆ๋‹ค.

2.5 TOC

  • ๊ฐœ๋ฐœ ์ด์œ  : ๋‚˜๋ฌด ์œ„ํ‚ค ๋ชฉ์ฐจ ์ฐพ์•„๊ฐ€๋Š” ๊ธฐ๋Šฅ์ด ๋ถ€๋Ÿฌ์›Œ์„œ.

  • ๊ตฌํ˜„ :

    • Heading ํ”Œ๋Ÿฌ๊ทธ์ธ์— TOC๋ฅผ ์œ„ํ•œ data-attribute๋ฅผ ์ถ”๊ฐ€ ๋ฐ ํ™œ์šฉํ•˜์—ฌ ํŒŒ์‹ฑ.

    • ResizeObserver๋ฅผ ํ†ตํ•œ Layout ๋ณ€๊ฒฝ ๊ฐ์ง€, Debouncing ์ ์šฉ์œผ๋กœ ์ตœ์ ํ™”.

  • ์–ด๋ ค์›€ : ํŒŒ์‹ฑํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ๊ตฌํ˜„๋˜์–ด ์—๋””ํ„ฐ Heading ํ”Œ๋Ÿฌ๊ทธ์ธ ๊ตฌํ˜„ ์‚ฌํ•ญ์„ ๋ชจ๋ฅด๋ฉด ์œ ์ง€ ๋ณด์ˆ˜ ํž˜๋“ฆ.

  • ์žฅ์  : ํ•œ๋ˆˆ์— ๋ชฉ์ฐจ๋ฅผ ๋ณผ ์ˆ˜ ์žˆ๊ณ  ์ฐพ์„ ์ˆ˜ ์žˆ๋‹ค.

2.6 ์ฒซ ์Šฌ๋ž˜์‰ฌ, ๋“œ๋ž˜๊ทธ ์ž๋™์™„์„ฑ

image.webpimage.webp
  • ๊ฐœ๋ฐœ ์ด์œ  : ๋…ธ์…˜ ์—๋””ํ„ฐ๋ฅผ ๋ ˆํผ๋Ÿฐ์Šค๋กœ ๋ดค์„ ๋•Œ ์ถฉ๋ถ„ํžˆ ์ข‹์•„ ๋ณด์ž„.

  • ๊ตฌํ˜„ :

    • ๋‹คํ–‰ํžˆ ๊ธฐ๋ณธ์ ์ธ ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์žˆ์–ด ํ•ด๋‹น ํ”Œ๋Ÿฌ๊ทธ์ธ ํ™œ์šฉ

    • ์ปค์Šคํ…€ํ•˜๊ฒŒ ์ถ”๊ฐ€ํ•˜๊ณ  ์‹ถ์€ ๊ธฐ๋Šฅ์„ ํ”Œ๋Ÿฌ๊ทธ์ธ์— ์ถ”๊ฐ€ํ•จ.

  • ์–ด๋ ค์›€ : Command๋ฅผ ๋‹ค ํŒŒ์•…ํ•˜๊ณ  ์ถ”๊ฐ€ํ•ด์•ผํ•˜๋Š”๋ฐ, ์ฝ”๋“œ๋ธ”๋Ÿญ์€ ๋ฐ”๋‹ฅ๋ถ€ํ„ฐ ๋งŒ๋“  ๊ธฐ๋Šฅ์ด๋ผ ์ปค๋งจ๋“œ๋ฅผ ์ง์ ‘ ์ถ”๊ฐ€ํ•ด์ค˜์•ผ ํ–ˆ์Œ.

  • ์žฅ์  : ๋งˆ์šฐ์Šค๋ฅผ ์ปจํŠธ๋กค ๋ฐ•์Šค๊นŒ์ง€ ์˜ฌ๋ฆฌ์ง€ ์•Š์•„์„œ ์ข‹์Œ.

3. ๊ธฐํƒ€ ๊ธฐ๋Šฅ

3.1 Iframe (CodePen)

  • ๊ฐœ๋ฐœ ์ด์œ  : ์–ธ์  ๊ฐ€ ์ฝ”๋“œ ์ž‘๋™๊นŒ์ง€ ๋ณด์—ฌ์ฃผ๋„๋ก ํ•ด์•ผํ•˜๋Š”๋ฐ, ์ฝ”๋“œ ํŽœ์„ ํ™œ์šฉํ•˜๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์„œ.

  • ๊ตฌํ˜„ :

    • iframe ์ ์šฉ์‹œ ๋ณด์•ˆ ๋ฌธ์ œ๊ฐ€ ์ƒ๊ธธ ์ˆ˜ ์žˆ์–ด์„œ CSP๋ฅผ ์ ์ ˆํ•˜๊ฒŒ ์‚ฌ์šฉ.

  • ์–ด๋ ค์›€ : ์™„์ „ํžˆ Third Party์ด๊ธฐ ๋•Œ๋ฌธ์— CSP ์˜ํ–ฅ์„ ๋งŽ์ด ๋ฐ›๋Š”๋ฐ ์‹ค์ œ ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธ๊ฐ€ ํž˜๋“ฆ.