Skip to content

Latest commit

ย 

History

History
676 lines (495 loc) ยท 29.5 KB

markdown-content.mdx

File metadata and controls

676 lines (495 loc) ยท 29.5 KB
title description i18nReady
Markdown & MDX
Astro์—์„œ Markdown ๋˜๋Š” MDX๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ฝ˜ํ…์ธ ๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์„ธ์š”.
true

import Since from '/components/Since.astro'; import { FileTree } from '@astrojs/starlight/components'; import RecipeLinks from "/components/RecipeLinks.astro"; import ReadMore from '~/components/ReadMore.astro'; import { Steps } from '@astrojs/starlight/components';

Markdown์€ ์ผ๋ฐ˜์ ์œผ๋กœ ๋ธ”๋กœ๊ทธ ๊ฒŒ์‹œ๋ฌผ ๋ฐ ๋ฌธ์„œ์™€ ๊ฐ™์ด ํ…์ŠคํŠธ๊ฐ€ ๋งŽ์€ ์ฝ˜ํ…์ธ ๋ฅผ ์ž‘์„ฑํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค. Astro์—๋Š” title, description, tags์™€ ๊ฐ™์€ ์‚ฌ์šฉ์ž ์ •์˜ ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ •์˜ํ•˜๊ธฐ ์œ„ํ•ด ํ”„๋ŸฐํŠธ๋งคํ„ฐ YAML๋„ ํฌํ•จํ•  ์ˆ˜ ์žˆ๋Š” ํ‘œ์ค€ Markdown ํŒŒ์ผ์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ง€์›์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค.

@astrojs/mdx ํ†ตํ•ฉ์ด ์„ค์น˜๋˜๋ฉด Astro๋Š” Markdown ์ฝ˜ํ…์ธ ์˜ JavaScript ํ‘œํ˜„์‹ ๋ฐ ์ปดํฌ๋„ŒํŠธ ์ง€์›๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•˜๋Š” MDX (.mdx) ํŒŒ์ผ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

Markdown ์ฝ˜ํ…์ธ ๋ฅผ ์ž‘์„ฑํ•˜๋ ค๋ฉด ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ํŒŒ์ผ ์ค‘ ํ•˜๋‚˜ ๋˜๋Š” ๋‘ ๊ฐ€์ง€๋ฅผ ๋ชจ๋‘ ์‚ฌ์šฉํ•˜์„ธ์š”!

Markdown ๋ฐ MDX ํŽ˜์ด์ง€

์ฝ˜ํ…์ธ  ์ปฌ๋ ‰์…˜

Astro์˜ ํŠน๋ณ„ํ•œ src/content/ ํด๋”์—์„œ Markdown ๋ฐ MDX ํŒŒ์ผ์„ ๊ด€๋ฆฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ฝ˜ํ…์ธ  ์ปฌ๋ ‰์…˜์€ ์ฝ˜ํ…์ธ ๋ฅผ ๊ตฌ์„ฑํ•˜๊ณ , ํ”„๋ŸฐํŠธ๋งคํ„ฐ์˜ ์œ ํšจ์„ฑ์„ ๊ฒ€์‚ฌํ•˜๊ณ , ์ฝ˜ํ…์ธ  ์ž‘์—… ์ค‘ ์ž๋™ TypeScript ํƒ€์ž… ์•ˆ์ „์„ฑ์„ ์ œ๊ณตํ•˜๋Š” ๋ฐ ๋„์›€์ด ๋ฉ๋‹ˆ๋‹ค.

- src/content/ - **newsletter/** - week-1.md - week-2.md - **authors/** - grace-hopper.md - alan-turing.md

Astro์˜ ์ฝ˜ํ…์ธ  ์ปฌ๋ ‰์…˜ ์‚ฌ์šฉ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.

ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ…

Astro๋Š” /src/pages/ ๋””๋ ‰ํ„ฐ๋ฆฌ์˜ .md (๋˜๋Š” ๋Œ€์ฒด ์ง€์› ํ™•์žฅ์ž) ๋˜๋Š” .mdx ํŒŒ์ผ์„ ํŽ˜์ด์ง€๋กœ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.

์ด ๋””๋ ‰ํ„ฐ๋ฆฌ๋‚˜ ํ•˜์œ„ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ํŒŒ์ผ์„ ๋ฐฐ์น˜ํ•˜๋ฉด ํŒŒ์ผ์˜ ๊ฒฝ๋กœ ์ด๋ฆ„์„ ์‚ฌ์šฉํ•˜์—ฌ ํŽ˜์ด์ง€ ๊ฒฝ๋กœ๊ฐ€ ์ž๋™์œผ๋กœ ๋นŒ๋“œ๋ฉ๋‹ˆ๋‹ค.

---
# Example: src/pages/page-1.md
title: Hello, World
---

# Hi there!

This Markdown file creates a page at `your-domain.com/page-1/`

It probably isn't styled much, but Markdown does support:
- **bold** and _italics._
- lists
- [links](https://astro.build)
- and more!

Astro์˜ ํŒŒ์ผ ๊ธฐ๋ฐ˜ ๋ผ์šฐํŒ… ๋˜๋Š” ๋™์  ๊ฒฝ๋กœ ์ƒ์„ฑ ์˜ต์…˜์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.

Markdown ๊ธฐ๋Šฅ

Astro๋Š” Markdown ๋ฐ MDX ํŒŒ์ผ์„ ์‚ฌ์šฉํ•  ๋•Œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์ถ”๊ฐ€ ๋‚ด์žฅ Markdown ๊ธฐ๋Šฅ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

ํ”„๋ŸฐํŠธ๋งคํ„ฐ layout

Astro๋Š” Astro ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ์— ๋Œ€ํ•œ ์ƒ๋Œ€ ๊ฒฝ๋กœ (๋˜๋Š” ๋ณ„์นญ)๋ฅผ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋Š” ํŠน๋ณ„ํ•œ ํ”„๋ŸฐํŠธ๋งคํ„ฐ layout ์†์„ฑ์ด ์žˆ๋Š” Markdown ๋ฐ MDX ํŽ˜์ด์ง€ (src/pages/์— ์œ„์น˜ํ•˜๋Š”)๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

---
# src/pages/posts/post-1.md
layout: ../../layouts/BlogPostLayout.astro
title: Astro in brief
author: Himanshu
description: Find out what makes Astro awesome!
--- 
This is a post written in Markdown.

๊ทธ๋Ÿฐ ๋‹ค์Œ Astro.props๋ฅผ ํ†ตํ•ด ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ์— ํŠน์ • ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด Astro.props.frontmatter๋ฅผ ํ†ตํ•ด frontmatter ์†์„ฑ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
// src/layouts/BlogPostLayout.astro
const {frontmatter} = Astro.props;
---
<html>
  <!-- ... -->
  <h1>{frontmatter.title}</h1>
  <h2>Post author: {frontmatter.author}</h2>
  <p>{frontmatter.description}</p>
  <slot /> <!-- Markdown ์ฝ˜ํ…์ธ ๊ฐ€ ์—ฌ๊ธฐ์— ์‚ฝ์ž…๋ฉ๋‹ˆ๋‹ค. -->
   <!-- ... -->
</html>

๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ์—์„œ Markdown ์Šคํƒ€์ผ์„ ์ง€์ •ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Markdown ๋ ˆ์ด์•„์›ƒ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด์„ธ์š”.

์ œ๋ชฉ ID

Markdown ๋ฐ MDX์˜ ์ œ๋ชฉ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ž๋™์œผ๋กœ ์•ต์ปค ๋งํฌ๊ฐ€ ์ œ๊ณต๋˜๋ฏ€๋กœ ํŽ˜์ด์ง€์˜ ํŠน์ • ์„น์…˜์— ์ง์ ‘ ์—ฐ๊ฒฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
title: My page of content
---
## Introduction

I can link internally to [my conclusion](#conclusion) on the same page when writing Markdown.

## Conclusion

I can use the URL `https://example.com/page-1/#introduction` to navigate directly to my Introduction on the page. 

Astro๋Š” github-slugger๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ id๋ผ๋Š” ์ œ๋ชฉ์„ ์ƒ์„ฑํ•ฉ๋‹ˆ๋‹ค. github-slugger ๋ฌธ์„œ์—์„œ ๋” ๋งŽ์€ ์˜ˆ์‹œ๋ฅผ ์ฐพ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํŠน์ˆ˜ ๋ฌธ์ž ์ด์Šค์ผ€์ดํ”„

ํŠน์ • ๋ฌธ์ž๋Š” Markdown ๋ฐ MDX์—์„œ ํŠน๋ณ„ํ•œ ์˜๋ฏธ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค. ํ‘œ์‹œํ•˜๋ ค๋ฉด ๋‹ค๋ฅธ ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•ด์•ผ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ ค๋ฉด ํ•ด๋‹น ๋ฌธ์ž์— ๋Œ€ํ•ด HTML ์—”ํ„ฐํ‹ฐ๋ฅผ ๋Œ€์‹  ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด <๊ฐ€ HTML ์š”์†Œ์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์œผ๋กœ ํ•ด์„๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด &lt;๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”. ๋˜๋Š” {๊ฐ€ MDX์—์„œ JavaScript ํ‘œํ˜„์‹์˜ ์‹œ์ž‘ ๋ถ€๋ถ„์œผ๋กœ ํ•ด์„๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด &lcub;๋ฅผ ์ž‘์„ฑํ•˜์„ธ์š”.

MDX ์ „์šฉ ๊ธฐ๋Šฅ

Astro MDX ํ†ตํ•ฉ์„ ์ถ”๊ฐ€ํ•˜๋ฉด JSX ๋ณ€์ˆ˜, ํ‘œํ˜„์‹, ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Markdown ์ž‘์„ฑ์ด ํ–ฅ์ƒ๋ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ MDX์˜ Markdown ์Šคํƒ€์ผ ํ”„๋ŸฐํŠธ๋งคํ„ฐ์— ๋Œ€ํ•œ ์ง€์›์„ ํฌํ•จํ•˜์—ฌ ํ‘œ์ค€ MDX์— ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ”„๋ŸฐํŠธ๋งคํ„ฐ layout ์†์„ฑ๊ณผ ๊ฐ™์€ Astro์˜ ๋‚ด์žฅ Markdown ๊ธฐ๋Šฅ ๋Œ€๋ถ€๋ถ„์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

.mdx ํŒŒ์ผ์€ Astro์˜ HTML๊ณผ ๊ฐ™์€ ๊ตฌ๋ฌธ์ด ์•„๋‹Œ MDX ๊ตฌ๋ฌธ์œผ๋กœ ์ž‘์„ฑ๋˜์–ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

MDX์—์„œ ๋‚ด๋ณด๋‚ธ ๋ณ€์ˆ˜ ์‚ฌ์šฉ

MDX๋Š” export ๊ตฌ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ MDX ์ฝ˜ํ…์ธ ์— ๋ณ€์ˆ˜๋ฅผ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ๋„๋ก ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ๋ณ€์ˆ˜๋Š” ํ…œํ”Œ๋ฆฟ ์ž์ฒด์—์„œ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์„ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ํŒŒ์ผ์„ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ช…๋ช…๋œ ์†์„ฑ์œผ๋กœ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด MDX ํŽ˜์ด์ง€ ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ title ํ•„๋“œ๋ฅผ ๋‚ด๋ณด๋‚ด {JSX ํ‘œํ˜„์‹}์˜ ์ œ๋ชฉ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export const title = 'My first MDX post'

# {title}

MDX์—์„œ ํ”„๋ŸฐํŠธ๋งคํ„ฐ ๋ณ€์ˆ˜ ์‚ฌ์šฉ

Astro MDX ํ†ตํ•ฉ์—๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ MDX์—์„œ ํ”„๋ŸฐํŠธ๋งคํ„ฐ ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ง€์›์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. Markdown ํŒŒ์ผ์—์„œ์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ํ”„๋ŸฐํŠธ๋งคํ„ฐ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•˜๋ฉด ์ด๋Ÿฌํ•œ ๋ณ€์ˆ˜์— ์•ก์„ธ์Šคํ•˜์—ฌ ํ…œํ”Œ๋ฆฟ, layout ์ปดํฌ๋„ŒํŠธ, ํŒŒ์ผ์„ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ช…๋ช…๋œ ์†์„ฑ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
layout: '../../layouts/BlogPostLayout.astro'
title: 'My first MDX post'
---

# {frontmatter.title}

MDX์—์„œ ์ปดํฌ๋„ŒํŠธ ์‚ฌ์šฉ

MDX ํ†ตํ•ฉ์„ ์„ค์น˜ํ•œ ํ›„ ๋‹ค๋ฅธ Astro ์ปดํฌ๋„ŒํŠธ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ Astro ์ปดํฌ๋„ŒํŠธ์™€ UI ํ”„๋ ˆ์ž„์›Œํฌ ์ปดํฌ๋„ŒํŠธ๋ฅผ MDX (.mdx) ํŒŒ์ผ๋กœ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

ํ•„์š”ํ•œ ๊ฒฝ์šฐ UI ํ”„๋ ˆ์ž„์›Œํฌ ์ปดํฌ๋„ŒํŠธ์— client:directive๋ฅผ ํฌํ•จํ•˜๋Š” ๊ฒƒ์„ ์žŠ์ง€ ๋งˆ์„ธ์š”!

MDX ๋ฌธ์„œ์—์„œ ๊ฐ€์ ธ์˜ค๊ธฐ ๋ฐ ๋‚ด๋ณด๋‚ด๊ธฐ ๊ตฌ๋ฌธ ์‚ฌ์šฉ์— ๋Œ€ํ•œ ์ถ”๊ฐ€ ์˜ˆ์‹œ๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

---
layout: ../layouts/BaseLayout.astro
title: About me
---
import Button from '../components/Button.astro';
import ReactCounter from '../components/ReactCounter.jsx';

I live on **Mars** but feel free to <Button title="Contact me" />.

Here is my counter component, working in MDX:

<ReactCounter client:load />

HTML ์š”์†Œ์— ๋งž์ถค ์ปดํฌ๋„ŒํŠธ ํ• ๋‹น

MDX๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Markdown ๊ตฌ๋ฌธ์„ ํ‘œ์ค€ HTML ์š”์†Œ ๋Œ€์‹  ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ์— ๋งคํ•‘ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ํ‘œ์ค€ Markdown ๊ตฌ๋ฌธ์œผ๋กœ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์„ ํƒํ•œ ์š”์†Œ์— ํŠน์ˆ˜ ์ปดํฌ๋„ŒํŠธ ์Šคํƒ€์ผ์„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ .mdx ํŒŒ์ผ๋กœ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ ํ‘œ์ค€ HTML ์š”์†Œ๋ฅผ ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ์— ๋งคํ•‘ํ•˜๋Š” components ๊ฐ์ฒด๋ฅผ ๋‚ด๋ณด๋ƒ…๋‹ˆ๋‹ค.

import Blockquote from '../components/Blockquote.astro';
export const components = {blockquote: Blockquote}

> This quote will be a custom Blockquote
---
const props = Astro.props;
---
<blockquote {...props} class="bg-blue-50 p-4">
  <span class="text-4xl text-blue-600 mb-2">โ€œ</span>
  <slot /> <!-- ํ•˜์œ„ ์ฝ˜ํ…์ธ ์—๋Š” `<slot/>`์„ ์ถ”๊ฐ€ํ•˜์„ธ์š”! -->
</blockquote>

์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ๋กœ ๋ฎ์–ด์“ธ ์ˆ˜ ์žˆ๋Š” HTML ์š”์†Œ์˜ ์ „์ฒด ๋ชฉ๋ก์„ ๋ณด๋ ค๋ฉด MDX ์›น์‚ฌ์ดํŠธ๋ฅผ ๋ฐฉ๋ฌธํ•˜์„ธ์š”.

Markdown ๊ฐ€์ ธ์˜ค๊ธฐ

Markdown ๋ฐ MDX ํŒŒ์ผ์„ Astro ํŒŒ์ผ๋กœ ์ง์ ‘ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด Markdown ์ฝ˜ํ…์ธ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ Astro์˜ JSX ์œ ์‚ฌ ํ‘œํ˜„์‹์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํ”„๋ŸฐํŠธ๋งคํ„ฐ ๊ฐ’๊ณผ ๊ฐ™์€ ๊ธฐํƒ€ ์†์„ฑ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํ•˜๋‚˜์˜ ํŠน์ • ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ Astro.glob()์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
// ๋‹จ์ผ ํŒŒ์ผ ๊ฐ€์ ธ์˜ค๊ธฐ
import * as myPost from '../pages/post/my-post.md';

// Astro.glob์„ ์‚ฌ์šฉํ•˜์—ฌ ์—ฌ๋Ÿฌ ํŒŒ์ผ ๊ฐ€์ ธ์˜ค๊ธฐ
const posts = await Astro.glob('../pages/post/*.md');
---

Astro ์ปดํฌ๋„ŒํŠธ์—์„œ Markdown ๋ฐ MDX ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ค๋ฉด ํ•ด๋‹น ๋‚ด๋ณด๋‚ธ ์†์„ฑ์ด ํฌํ•จ๋œ ๊ฐ์ฒด๋ฅผ ์–ป๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

---
title: 'The greatest post of all time'
author: 'Ben'
---

Here is my _great_ post!
---
import * as greatPost from '../pages/post/great-post.md';

const posts = await Astro.glob('../pages/post/*.md');
---

<p>{greatPost.frontmatter.title}</p>
<p>Written by: {greatPost.frontmatter.author}</p>

<p>Post Archive:</p>
<ul>
  {posts.map(post => <li><a href={post.url}>{post.frontmatter.title}</a></li>)}
</ul>

MDX ํŒŒ์ผ์—์„œ๋Š” frontmatter ๋ฐ export ๋ฌธ ๋ชจ๋‘์—์„œ ์†์„ฑ์— ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
title: 'The greatest post of all time'
author: 'Ben'
---
export const description = 'Get comfortable! This is going to be a great read.'

Here is my _great_ post!
---
import * as greatPost from '../pages/post/mdx-post.mdx';
---

<p>{greatPost.frontmatter.title}</p>
<p>Written by: {greatPost.frontmatter.author}</p>
<p>{greatPost.description}</p>

TypeScript ์ œ๋„ค๋ฆญ์„ ์‚ฌ์šฉํ•˜์—ฌ frontmatter ๋ณ€์ˆ˜์— ๋Œ€ํ•œ ํƒ€์ž…์„ ์„ ํƒ์ ์œผ๋กœ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
interface Frontmatter {
  title: string;
  description?: string;
}
const posts = await Astro.glob<Frontmatter>('../pages/post/*.md');
---

<ul>
  {posts.map(post => <li>{post.frontmatter.title}</li>)}
  <!-- post.frontmatter.title์€ `string`์ด ๋ฉ๋‹ˆ๋‹ค! -->
</ul>

๋‚ด๋ณด๋‚ธ ์†์„ฑ

:::note[Astro ๋ ˆ์ด์•„์›ƒ์„ ์‚ฌ์šฉํ•˜์‹œ๋‚˜์š”?] Astro์˜ ํŠน์ˆ˜ํ•œ ํ”„๋ŸฐํŠธ๋งคํ„ฐ layout์„ ์‚ฌ์šฉํ•  ๋•Œ Astro ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ๋กœ ๋‚ด๋ณด๋‚ธ ์†์„ฑ์„ ํ™•์ธํ•˜์„ธ์š”. :::

import ๋ฌธ์ด๋‚˜ Astro.glob()์„ ์‚ฌ์šฉํ•  ๋•Œ .astro ์ปดํฌ๋„ŒํŠธ์— ๋‹ค์Œ ์†์„ฑ์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  • file - ์ ˆ๋Œ€ ํŒŒ์ผ ๊ฒฝ๋กœ (์˜ˆ: /home/user/projects/.../file.md).
  • url - ํŽ˜์ด์ง€์ธ ๊ฒฝ์šฐ ํŽ˜์ด์ง€์˜ URL (์˜ˆ: /en/guides/markdown-content).
  • frontmatter - ํŒŒ์ผ์˜ YAML ํ”„๋ŸฐํŠธ๋งคํ„ฐ์— ์ง€์ •๋œ ๋ชจ๋“  ๋ฐ์ดํ„ฐ๋ฅผ ํฌํ•จํ•ฉ๋‹ˆ๋‹ค.
  • getHeadings - ํŒŒ์ผ์˜ ๋ชจ๋“  ์ œ๋ชฉ (์˜ˆ: h1 -> h6 ์š”์†Œ)์˜ ๋ฐฐ์—ด์„ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋น„๋™๊ธฐ ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ๊ฐ ์ œ๋ชฉ์˜ slug๋Š” ํŠน์ • ์ œ๋ชฉ์— ๋Œ€ํ•ด ์ƒ์„ฑ๋œ ID์— ํ•ด๋‹นํ•˜๋ฉฐ, ์•ต์ปค ๋งํฌ์— ์‚ฌ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋ชฉ๋ก์€ ๋‹ค์Œ ํƒ€์ž…์„ ๋”ฐ๋ฆ…๋‹ˆ๋‹ค: { depth: number; slug: string; text: string }[].
  • Content - ํŒŒ์ผ์˜ ์ „์ฒด ๋ Œ๋”๋ง๋œ ์ฝ˜ํ…์ธ ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ์ž…๋‹ˆ๋‹ค.
  • (Markdown๋งŒ ํ•ด๋‹น) rawContent() - ์›์‹œ Markdown ๋ฌธ์„œ๋ฅผ ๋ฌธ์ž์—ด๋กœ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค.
  • (Markdown๋งŒ ํ•ด๋‹น) compiledContent() - HTML ๋ฌธ์ž์—ด๋กœ ์ปดํŒŒ์ผ๋œ Markdown ๋ฌธ์„œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ํ•จ์ˆ˜์ž…๋‹ˆ๋‹ค. ์—ฌ๊ธฐ์—๋Š” ํ”„๋ŸฐํŠธ๋งคํ„ฐ์— ๊ตฌ์„ฑ๋œ ๋ ˆ์ด์•„์›ƒ์ด ํฌํ•จ๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค! Markdown ๋ฌธ์„œ ์ž์ฒด๋งŒ HTML๋กœ ๋ฐ˜ํ™˜๋ฉ๋‹ˆ๋‹ค.
  • (MDX์—๋งŒ ํ•ด๋‹น) - MDX ํŒŒ์ผ์€ export ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

Content ์ปดํฌ๋„ŒํŠธ

Markdown ๋˜๋Š” MDX ํŒŒ์ผ์˜ ์ „์ฒด ๋ Œ๋”๋ง๋œ ์ฝ˜ํ…์ธ ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด Content๋ฅผ ๊ฐ€์ ธ์˜ต๋‹ˆ๋‹ค.

---
import {Content as PromoBanner} from '../components/promoBanner.md';
---

<h2>Today's promo</h2>
<PromoBanner />

์˜ˆ: ๋™์  ํŽ˜์ด์ง€ ๋ผ์šฐํŒ…

ํŽ˜์ด์ง€ ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด Markdown/MDX ํŒŒ์ผ์„ src/pages/ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ๋‘๋Š” ๋Œ€์‹  ํŽ˜์ด์ง€๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Markdown ์ฝ˜ํ…์ธ ์— ์•ก์„ธ์Šคํ•˜๋ ค๋ฉด Astro ํŽ˜์ด์ง€์˜ props๋ฅผ ํ†ตํ•ด <Content/> ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ „๋‹ฌํ•˜์„ธ์š”. ๊ทธ๋Ÿฐ ๋‹ค์Œ Astro.props์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฒ€์ƒ‰ํ•˜์—ฌ ํŽ˜์ด์ง€ ํ…œํ”Œ๋ฆฟ์— ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
export async function getStaticPaths() {
  const posts = await Astro.glob('../posts/**/*.md')

  return posts.map(post => ({
    params: { 
      slug: post.frontmatter.slug 
    },
    props: {
      post
    },
  }))
}

const { Content } = Astro.props.post
---
<article>
  <Content/>
</article>

MDX ์ „์šฉ ๋‚ด๋ณด๋‚ด๊ธฐ

MDX ํŒŒ์ผ์€ export ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฐ์ดํ„ฐ๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

์˜ˆ๋ฅผ ๋“ค์–ด MDX ํŽ˜์ด์ง€ ๋˜๋Š” ์ปดํฌ๋„ŒํŠธ์—์„œ title ํ•„๋“œ๋ฅผ ๋‚ด๋ณด๋‚ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

export const title = 'My first MDX post'

์ด title์€ import ๋ฐ Astro.glob() ๋ฌธ์—์„œ ์•ก์„ธ์Šคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
// src/pages/index.astro
const posts = await Astro.glob('./*.mdx');
---

{posts.map(post => <p>{post.title}</p>)}

๊ฐ€์ ธ์˜จ MDX๊ฐ€ ์žˆ๋Š” ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ

๊ฐ€์ ธ์˜จ MDX ์ฝ˜ํ…์ธ ๋ฅผ ๋ Œ๋”๋งํ•  ๋•Œ ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ๋Š” components prop์„ ํ†ตํ•ด ์ „๋‹ฌ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

---
import { Content, components } from '../content.mdx';
import Heading from '../Heading.astro';
---
<!-- # ๊ตฌ๋ฌธ์— ๋Œ€ํ•œ ์‚ฌ์šฉ์ž ์ •์˜ <h1>์„ ์ƒ์„ฑํ•˜๊ณ  `content.mdx`์— ์ •์˜๋œ ๋ชจ๋“  ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. -->
<Content components={{...components, h1: Heading }} />

:::note MDX ํŒŒ์ผ์— ์ •์˜๋˜๊ณ  ๋‚ด๋ณด๋‚ธ ์‚ฌ์šฉ์ž ์ •์˜ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ ธ์˜จ ๋‹ค์Œ components ์†์„ฑ์„ ํ†ตํ•ด <Content /> ์ปดํฌ๋„ŒํŠธ์— ๋‹ค์‹œ ์ „๋‹ฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. :::

Markdown ๋ฐ MDX ๊ตฌ์„ฑ

Astro์˜ Markdown ์ง€์›์€ ํ™œ์„ฑ ์ƒํƒœ๊ณ„๋ฅผ ๊ฐ–์ถ˜ ๊ฐ•๋ ฅํ•œ ๊ตฌ๋ฌธ ๋ถ„์„ ๋ฐ ์ฒ˜๋ฆฌ ๋„๊ตฌ์ธ remark๋ฅผ ํ†ตํ•ด ์ œ๊ณต๋ฉ๋‹ˆ๋‹ค. Pandoc ๋ฐ markdown-it๊ณผ ๊ฐ™์€ ๋‹ค๋ฅธ Markdown ํŒŒ์„œ๋Š” ํ˜„์žฌ ์ง€์›๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

Astro๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ GitHub-flavored Markdown ๋ฐ SmartyPants ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํ…์ŠคํŠธ์—์„œ ํด๋ฆญ ๊ฐ€๋Šฅํ•œ ๋งํฌ ์ƒ์„ฑ, ์ธ์šฉ ๋ฐ em-dashes ์„œ์‹ ์ง€์ •๊ณผ ๊ฐ™์€ ๋ช‡ ๊ฐ€์ง€ ์žฅ์ ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

astro.config.mjs ํŒŒ์ผ์—์„œ remark๊ฐ€ Markdown์„ ๊ตฌ๋ฌธ ๋ถ„์„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Markdown ๊ตฌ์„ฑ ์˜ต์…˜์˜ ์ „์ฒด ๋ชฉ๋ก์„ ํ™•์ธํ•˜์„ธ์š”.

Markdown ํ”Œ๋Ÿฌ๊ทธ์ธ

Astro๋Š” Markdown ๋ฐ MDX์— ๋Œ€ํ•œ ํƒ€์‚ฌ remark ๋ฐ rehype ํ”Œ๋Ÿฌ๊ทธ์ธ ์ถ”๊ฐ€๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜๋ฉด ๋ชฉ์ฐจ ์ž๋™ ์ƒ์„ฑ, ์ ‘๊ทผ ๊ฐ€๋Šฅํ•œ ์ด๋ชจํ‹ฐ์ฝ˜ ๋ผ๋ฒจ ์ ์šฉ, Markdown ์Šคํƒ€์ผ ์ง€์ •๊ณผ ๊ฐ™์€ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์œผ๋กœ Markdown์„ ํ™•์žฅํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

awesome-remark ๋ฐ awesome-rehype์™€ ๊ฐ™์€ ์ธ๊ธฐ ํ”Œ๋Ÿฌ๊ทธ์ธ๋“ค์„ ์ฐพ์•„๋ณด์‹œ๊ธฐ ๋ฐ”๋ž๋‹ˆ๋‹ค! ๊ตฌ์ฒด์ ์ธ ์„ค์น˜ ์ง€์นจ์€ ๊ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ ์ž์ฒด README๋ฅผ ์ฐธ์กฐํ•˜์„ธ์š”.

์ด ์˜ˆ์‹œ์—์„œ๋Š” Markdown ๋ฐ MDX ํŒŒ์ผ ๋ชจ๋‘์— remark-toc ๋ฐ rehype-accessible-emojis๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

import { defineConfig } from 'astro/config';
import remarkToc from 'remark-toc';
import { rehypeAccessibleEmojis } from 'rehype-accessible-emojis';

export default defineConfig({
  markdown: {
    // .md ๋ฐ .mdx ํŒŒ์ผ์— ์ ์šฉ๋จ
    remarkPlugins: [remarkToc, { heading: 'toc', maxDepth: 3 }],
    rehypePlugins: [rehypeAccessibleEmojis],
  },
});

์ œ๋ชฉ ID ๋ฐ ํ”Œ๋Ÿฌ๊ทธ์ธ

Astro๋Š” Markdown ๋ฐ MDX ํŒŒ์ผ์˜ ๋ชจ๋“  ์ œ๋ชฉ ์š”์†Œ (<h1> ~ <h6>)์— id ์†์„ฑ์„ ์‚ฝ์ž…ํ•˜๊ณ  Markdown ๋‚ด๋ณด๋‚ธ ์†์„ฑ์—์„œ ์ด๋Ÿฌํ•œ ID๋ฅผ ๊ฒ€์ƒ‰ํ•˜๊ธฐ ์œ„ํ•œ getHeadings() ์œ ํ‹ธ๋ฆฌํ‹ฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

id ์†์„ฑ (์˜ˆ: rehype-slug)์„ ์‚ฝ์ž…ํ•˜๋Š” rehype ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ด๋Ÿฌํ•œ ์ œ๋ชฉ ID๋ฅผ ๋งž์ถค์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. Astro์˜ ๊ธฐ๋ณธ๊ฐ’ ๋Œ€์‹  ์‚ฌ์šฉ์ž ์ •์˜ ID๊ฐ€ HTML ์ถœ๋ ฅ๊ณผ getHeadings()์— ์˜ํ•ด ๋ฐ˜ํ™˜๋œ ํ•ญ๋ชฉ์— ๋ฐ˜์˜๋ฉ๋‹ˆ๋‹ค.

๊ธฐ๋ณธ์ ์œผ๋กœ Astro๋Š” rehype ํ”Œ๋Ÿฌ๊ทธ์ธ์ด ์‹คํ–‰๋œ ํ›„ id ์†์„ฑ์„ ์ฃผ์ž…ํ•ฉ๋‹ˆ๋‹ค. ์‚ฌ์šฉ์ž ์ •์˜ rehype ํ”Œ๋Ÿฌ๊ทธ์ธ ์ค‘ ํ•˜๋‚˜๊ฐ€ Astro์—์„œ ์‚ฝ์ž…ํ•œ ID์— ์•ก์„ธ์Šคํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ Astro์˜ rehypeHeadingIds ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์ง์ ‘ ๊ฐ€์ ธ์™€ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ํ”Œ๋Ÿฌ๊ทธ์ธ ์•ž์— rehypeHeadingIds๋ฅผ ์ถ”๊ฐ€ํ•˜์„ธ์š”.

import { defineConfig } from 'astro/config';
import { rehypeHeadingIds } from '@astrojs/markdown-remark';
import { otherPluginThatReliesOnHeadingIDs } from 'some/plugin/source';

export default defineConfig({
  markdown: {
    rehypePlugins: [
      rehypeHeadingIds,
      otherPluginThatReliesOnHeadingIDs,
    ],
  },
});

:::note getHeadings()๋Š” Markdown ๋˜๋Š” MDX ํŒŒ์ผ์— ์ง์ ‘ ์ž‘์„ฑ๋œ ์ œ๋ชฉ๋งŒ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค. MDX ํŒŒ์ผ์ด ์ž์ฒด ์ œ๋ชฉ์„ ํฌํ•จํ•˜๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒฝ์šฐ, getHeadings()์— ์˜ํ•ด ๋ฐ˜ํ™˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. :::

ํ”Œ๋Ÿฌ๊ทธ์ธ ๋งž์ถค์„ค์ •

ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉ์ž ์ •์˜ํ•˜๋ ค๋ฉด ์ค‘์ฒฉ ๋ฐฐ์—ด์—์„œ ํ”Œ๋Ÿฌ๊ทธ์ธ ๋’ค์— ์˜ต์…˜ ๊ฐ์ฒด๋ฅผ ์ œ๊ณตํ•˜์„ธ์š”.

์•„๋ž˜ ์˜ˆ์‹œ์—์„œ๋Š” remarkToc ํ”Œ๋Ÿฌ๊ทธ์ธ์— heading ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ชฉ์ฐจ ์œ„์น˜๋ฅผ ๋ณ€๊ฒฝํ•˜๊ณ , rehype-autolink-headings ํ”Œ๋Ÿฌ๊ทธ์ธ์— behavior ์˜ต์…˜์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์ œ๋ชฉ ํ…์ŠคํŠธ ๋’ค์— ์•ต์ปค ํƒœ๊ทธ๋ฅผ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

import remarkToc from 'remark-toc';
import rehypeSlug from 'rehype-slug';
import rehypeAutolinkHeadings from 'rehype-autolink-headings';

export default {
  markdown: {
    remarkPlugins: [ [remarkToc, { heading: "contents"} ] ],
    rehypePlugins: [rehypeSlug, [rehypeAutolinkHeadings, { behavior: 'append' }]],
  },
}

ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๋ฐฉ์‹์œผ๋กœ ํ”„๋ŸฐํŠธ๋งคํ„ฐ ์ˆ˜์ •ํ•˜๊ธฐ

:::note ์ฝ˜ํ…์ธ  ์ปฌ๋ ‰์…˜์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, "ํ”„๋ŸฐํŠธ๋งคํ„ฐ๋ฅผ Remark๋กœ ์ˆ˜์ •ํ•˜๊ธฐ"์„ ์ฐธ์กฐํ•˜์„ธ์š”. :::

remark ๋˜๋Š” rehype ํ”Œ๋Ÿฌ๊ทธ์ธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  Markdown ๋ฐ MDX ํŒŒ์ผ์— ํ”„๋ŸฐํŠธ๋งคํ„ฐ ์†์„ฑ์„ ์ถ”๊ฐ€ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

1. ํ”Œ๋Ÿฌ๊ทธ์ธ์˜ `file` ์ธ์ˆ˜์—์„œ `data.astro.frontmatter` ์†์„ฑ์— `customProperty`๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
```js title="example-remark-plugin.mjs"
export function exampleRemarkPlugin() {
  // ๋ชจ๋“  remark ๋ฐ rehype ํ”Œ๋Ÿฌ๊ทธ์ธ์€ ๋ณ„๋„์˜ ํ•จ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•ฉ๋‹ˆ๋‹ค.
  return function (tree, file) {
    file.data.astro.frontmatter.customProperty = 'Generated property';
  }
}
```

:::tip
<Since v="2.0.0" />

`data.astro.frontmatter`์—๋Š” ํŠน์ • Markdown ๋˜๋Š” MDX ๋ฌธ์„œ์˜ ๋ชจ๋“  ์†์„ฑ์ด ํฌํ•จ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๊ธฐ์กด ํ”„๋ŸฐํŠธ๋งคํ„ฐ ์†์„ฑ์„ ์ˆ˜์ •ํ•˜๊ฑฐ๋‚˜ ๊ธฐ์กด ํ”„๋ŸฐํŠธ๋งคํ„ฐ์—์„œ ์ƒˆ ์†์„ฑ์„ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
:::
  1. ์ด ํ”Œ๋Ÿฌ๊ทธ์ธ์„ markdown ๋˜๋Š” mdx ํ†ตํ•ฉ ๊ตฌ์„ฑ์— ์ ์šฉํ•˜์„ธ์š”.

    import { defineConfig } from 'astro/config';
    import { exampleRemarkPlugin } from './example-remark-plugin.mjs';
    
    export default defineConfig({
      markdown: {
        remarkPlugins: [exampleRemarkPlugin]
      },
    });

    ๋˜๋Š”

    import { defineConfig } from 'astro/config';
    import { exampleRemarkPlugin } from './example-remark-plugin.mjs';
    
    export default defineConfig({
      integrations: [
        mdx({
          remarkPlugins: [exampleRemarkPlugin],
        }),
      ],
    });

์ด์ œ ๋ชจ๋“  Markdown ๋˜๋Š” MDX ํŒŒ์ผ์˜ ํ”„๋ŸฐํŠธ๋งคํ„ฐ์— customProperty๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ Markdown์„ ๊ฐ€์ ธ์˜ฌ ๋•Œ ๋ ˆ์ด์•„์›ƒ์˜ Astro.props.frontmatter ์†์„ฑ์—์„œ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

<RecipeLinks slugs={["ko/recipes/reading-time"]} />

MDX์—์„œ Markdown ๊ตฌ์„ฑ ํ™•์žฅ

Astro์˜ MDX ํ†ตํ•ฉ์€ ๊ธฐ๋ณธ์ ์œผ๋กœ ํ”„๋กœ์ ํŠธ์˜ ๊ธฐ์กด Markdown ๊ตฌ์„ฑ์„ ํ™•์žฅํ•ฉ๋‹ˆ๋‹ค. ๊ฐœ๋ณ„ ์˜ต์…˜์„ ์žฌ์ •์˜ํ•˜๋ ค๋ฉด MDX ๊ตฌ์„ฑ์—์„œ ํ•ด๋‹น ์˜ต์…˜์„ ์ง€์ •ํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.

๋‹ค์Œ ์˜ˆ์‹œ์—์„œ๋Š” GitHub ๊ธฐ๋ฐ˜ Markdown์„ ๋น„ํ™œ์„ฑํ™”ํ•˜๊ณ  MDX ํŒŒ์ผ์— ๋Œ€ํ•ด ๋‹ค๋ฅธ remark ํ”Œ๋Ÿฌ๊ทธ์ธ ์„ธํŠธ๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  markdown: {
    syntaxHighlight: 'prism',
    remarkPlugins: [remarkPlugin1],
    gfm: true,
  },
  integrations: [
    mdx({
      // Markdown์—์„œ ์ƒ์†๋œ `syntaxHighlight`

      // Markdown `remarkPlugins`๊ฐ€ ๋ฌด์‹œ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
      // `remarkPlugin2`๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค.
      remarkPlugins: [remarkPlugin2],
      // `gfm`์ด `false`๋กœ ์žฌ์ •์˜๋จ
      gfm: false,
    })
  ]
});

MDX์—์„œ Markdown ๊ตฌ์„ฑ์„ ํ™•์žฅํ•˜์ง€ ์•Š์œผ๋ ค๋ฉด extendMarkdownConfig ์˜ต์…˜ (๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋จ)์„ false๋กœ ์„ค์ •ํ•˜์„ธ์š”.

import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';

export default defineConfig({
  markdown: {
    remarkPlugins: [remarkPlugin],
  },
  integrations: [
    mdx({
      // Markdown ๊ตฌ์„ฑ์€ ์ด์ œ ๋ฌด์‹œ๋ฉ๋‹ˆ๋‹ค.
      extendMarkdownConfig: false,
      // 'remarkPlugins'๊ฐ€ ์ ์šฉ๋˜์ง€ ์•Š์•˜์Šต๋‹ˆ๋‹ค.
    })
  ]
});

๊ตฌ๋ฌธ ๊ฐ•์กฐ

Astro์—๋Š” Shiki ๋ฐ Prism์— ๋Œ€ํ•œ ์ง€์›์ด ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋‹ค์Œ์— ๋Œ€ํ•œ ๊ตฌ๋ฌธ ๊ฐ•์กฐ๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

Shiki๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ ํ™œ์„ฑํ™”๋˜์–ด ์žˆ์œผ๋ฉฐ github-dark ํ…Œ๋งˆ๋กœ ์‚ฌ์ „ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ปดํŒŒ์ผ๋œ ์ถœ๋ ฅ์€ ์™ธ๋ถ€ CSS ํด๋ž˜์Šค, ์Šคํƒ€์ผ์‹œํŠธ ๋˜๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก JS๊ฐ€ ์—†๋Š” ์ธ๋ผ์ธ ์Šคํƒ€์ผ๋กœ ์ œํ•œ๋ฉ๋‹ˆ๋‹ค.

Shiki ๊ตฌ์„ฑ

Shiki๋Š” ๊ธฐ๋ณธ ๊ตฌ๋ฌธ ๊ฐ•์กฐ ๋„๊ตฌ์ž…๋‹ˆ๋‹ค. ๋‹ค์Œ๊ณผ ๊ฐ™์ด shikiConfig ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด ๋ชจ๋“  ์˜ต์…˜์„ ๊ตฌ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { defineConfig } from 'astro/config';

export default defineConfig({
  markdown: {
    shikiConfig: {
      // Shiki์— ๋‚ด์žฅ๋œ ํ…Œ๋งˆ ์ค‘์—์„œ ์„ ํƒํ•˜๊ฑฐ๋‚˜ ์ง์ ‘ ์ถ”๊ฐ€ํ•˜์„ธ์š”.
      // https://shiki.style/themes
      theme: 'dracula',
      // ๋˜๋Š” ์—ฌ๋Ÿฌ ํ…Œ๋งˆ๋ฅผ ์ œ๊ณตํ•˜์„ธ์š”.
      // https://shiki.style/guide/dual-themes#light-dark-dual-themes
      themes: {
        light: 'github-light',
        dark: 'github-dark',
      },
      // ๋งž์ถค ์–ธ์–ด ์ถ”๊ฐ€
      // ์ฐธ๊ณ : Shiki์—๋Š” .astro๋ฅผ ํฌํ•จํ•˜์—ฌ ์ˆ˜๋งŽ์€ ์–ธ์–ด๊ฐ€ ๋‚ด์žฅ๋˜์–ด ์žˆ์Šต๋‹ˆ๋‹ค!
      // https://shiki.style/languages
      langs: [],
      // ๊ฐ€๋กœ ์Šคํฌ๋กค์„ ๋ฐฉ์ง€ํ•˜๋ ค๋ฉด word wrap์„ ํ™œ์„ฑํ™”ํ•˜์„ธ์š”.
      wrap: true,
      // ๋งž์ถค transformers ์ถ”๊ฐ€: https://shiki.style/guide/transformers
      // ์ผ๋ฐ˜ transformers ์ฐพ๊ธฐ: https://shiki.style/packages/transformers
      transformers: [],
    },
  },
});

๋‚˜๋งŒ์˜ ํ…Œ๋งˆ ์ถ”๊ฐ€ํ•˜๊ธฐ

Shiki์˜ ์‚ฌ์ „ ์ •์˜๋œ ํ…Œ๋งˆ ์ค‘ ํ•˜๋‚˜๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋Œ€์‹  ๋กœ์ปฌ ํŒŒ์ผ์—์„œ ์‚ฌ์šฉ์ž ์ •์˜ ํ…Œ๋งˆ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { defineConfig } from 'astro/config';
import customTheme from './my-shiki-theme.json';

export default defineConfig({
  markdown: {
    shikiConfig: { theme: customTheme },
  },
});

๋˜ํ•œ ํ…Œ๋งˆ, ๋ฐ์€ ๋ชจ๋“œ์™€ ์–ด๋‘์šด ๋ชจ๋“œ ์ „ํ™˜ ๋˜๋Š” CSS ๋ณ€์ˆ˜๋ฅผ ํ†ตํ•œ ์Šคํƒ€์ผ ์ง€์ •์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๋ ค๋ฉด Shiki์˜ ์ž์ฒด ํ…Œ๋งˆ ๋ฌธ์„œ๋ฅผ ์ฝ์–ด๋ณด๋Š” ๊ฒƒ์ด ์ข‹์Šต๋‹ˆ๋‹ค.

๊ธฐ๋ณธ ๊ตฌ๋ฌธ ๊ฐ•์กฐ ๋ชจ๋“œ ๋ณ€๊ฒฝ

๊ธฐ๋ณธ์ ์œผ๋กœ prism'์œผ๋กœ ์ „ํ™˜ํ•˜๊ฑฐ๋‚˜ ๊ตฌ๋ฌธ ๊ฐ•์กฐ๋ฅผ ์™„์ „ํžˆ ๋น„ํ™œ์„ฑํ™”ํ•˜๋ ค๋ฉด markdown.syntaxHighlight ๊ตฌ์„ฑ ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import { defineConfig } from 'astro/config';

export default defineConfig({
  markdown: {
    // 'shiki' (๊ธฐ๋ณธ๊ฐ’), 'prism' ๋˜๋Š” ๊ฐ•์กฐ๋ฅผ ๋น„ํ™œ์„ฑํ™” ํ•˜๊ธฐ ์œ„ํ•œ false์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    syntaxHighlight: 'prism',
  },
});

Prism ๊ตฌ์„ฑ

Prism์„ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ์„ ํƒํ•œ ๊ฒฝ์šฐ Astro๋Š” ๋Œ€์‹  Prism์˜ CSS ํด๋ž˜์Šค๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ตฌ๋ฌธ ๊ฐ•์กฐ๋ฅผ ํ‘œ์‹œํ•˜๋ ค๋ฉด ์ž์‹ ๋งŒ์˜ CSS ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ๊ฐ€์ ธ์™€์•ผ ํ•ฉ๋‹ˆ๋‹ค.

1. ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ [Prism ํ…Œ๋งˆ](https://github.com/PrismJS/prism-themes)์—์„œ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์ง„ ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ์„ ํƒํ•ฉ๋‹ˆ๋‹ค.
  1. ์ด ์Šคํƒ€์ผ์‹œํŠธ๋ฅผ ํ”„๋กœ์ ํŠธ์˜ public/ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์ถ”๊ฐ€ํ•˜์„ธ์š”.

  2. <link> ํƒœ๊ทธ๋ฅผ ํ†ตํ•ด ๋ ˆ์ด์•„์›ƒ ์ปดํฌ๋„ŒํŠธ์— ์žˆ๋Š” ํŽ˜์ด์ง€์˜ <head>์— ์ด๋ฅผ ๋กœ๋“œํ•ฉ๋‹ˆ๋‹ค. (Prism ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ•์„ ์ฐธ๊ณ ํ•˜์„ธ์š”.)

์˜ต์…˜ ๋ฐ ์‚ฌ์šฉ๋ฒ•์„ ์•Œ์•„๋ณด๋ ค๋ฉด Prism์—์„œ ์ง€์›ํ•˜๋Š” ์–ธ์–ด ๋ชฉ๋ก์„ ๋ฐฉ๋ฌธํ•˜์„ธ์š”.

์›๊ฒฉ ๋งˆํฌ๋‹ค์šด ๊ฐ€์ ธ์˜ค๊ธฐ

Astro๋Š” ์ฃผ๋กœ ํ”„๋กœ์ ํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ๋กœ์ปฌ Markdown ํŒŒ์ผ์šฉ์œผ๋กœ ์„ค๊ณ„๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ์›๊ฒฉ ์†Œ์Šค์—์„œ Markdown์„ ๊ฐ€์ ธ์™€์•ผ ํ•˜๋Š” ํŠน์ • ๊ฒฝ์šฐ๊ฐ€ ์žˆ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์›น ์‚ฌ์ดํŠธ๋ฅผ ๊ตฌ์ถ•ํ•  ๋•Œ (๋˜๋Š” SSR์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ, ์‚ฌ์šฉ์ž๊ฐ€ ์›น ์‚ฌ์ดํŠธ์— ์š”์ฒญํ•  ๋•Œ) ์›๊ฒฉ API์—์„œ Markdown์„ ๊ฐ€์ ธ์˜ค๊ณ  ๋ Œ๋”๋งํ•ด์•ผ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Astro์—๋Š” ์›๊ฒฉ Markdown์— ๋Œ€ํ•œ ๊ธฐ๋ณธ ์ง€์›์ด ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š์Šต๋‹ˆ๋‹ค! ์›๊ฒฉ Markdown์„ ๊ฐ€์ ธ์™€ HTML๋กœ ๋ Œ๋”๋งํ•˜๋ ค๋ฉด npm์—์„œ ์ž์ฒด Markdown ํŒŒ์„œ๋ฅผ ์„ค์น˜ํ•˜๊ณ  ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” Astro์˜ ๊ธฐ๋ณธ ์ œ๊ณต Markdown ๋ฐ ์‚ฌ์šฉ์ž๊ฐ€ ๊ตฌ์„ฑํ•œ MDX ์„ค์ •์—์„œ ์ƒ์†๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ํ”„๋กœ์ ํŠธ์— ์ด๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— ์ด๋Ÿฌํ•œ ์ œํ•œ ์‚ฌํ•ญ์„ ์ดํ•ดํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.

---
// ์˜ˆ: ์›๊ฒฉ API์—์„œ ๋งˆํฌ๋‹ค์šด ๊ฐ€์ ธ์˜ค๊ธฐ
// ๋Ÿฐํƒ€์ž„์— HTML๋กœ ๋ Œ๋”๋งํ•ฉ๋‹ˆ๋‹ค.
// "marked" ์‚ฌ์šฉ (https://github.com/markedjs/marked)
import { marked } from 'marked';
const response = await fetch('https://raw.githubusercontent.com/wiki/adam-p/markdown-here/Markdown-Cheatsheet.md');
const markdown = await response.text();
const content = marked.parse(markdown);
---
<article set:html={content} />