๋ฐ์ํ
๐ Next.js ์ markdown ์ค์น ํ๊ธฐ
# โจ Next.js์์ MDX ์ฌ์ฉํ๊ธฐ
## ๐ฆ MDX ๊ด๋ จ ํจํค์ง ์ค์น
yarn add @next/mdx @mdx-js/loader @mdx-js/react
yarn add --dev @types/mdx
@next/mdx
: Next.js์์ MDX๋ฅผ ์ง์ํ๊ธฐ ์ํ ๊ณต์ ํจํค์ง@mdx-js/loader
: MDX ๋ฌธ์๋ฅผ ์ปดํ์ผํ๋ Webpack ๋ก๋@mdx-js/react
: MDX ๋ฌธ์ ๋ด์์ React ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํฉ๋๋ค.@types/mdx
: TypeScript ํ๋ก์ ํธ์์ MDX ํ์ผ์ ๋ํ ํ์ ์ง์์ ์ ๊ณตํฉ๋๋ค.remark-prism
: ๋งํฌ๋ค์ด ๋ด ์ฝ๋ ๋ธ๋ก์ ํ์ด๋ผ์ดํ ํ๊ธฐ ์ํ ํจํค์ง (์ ํ์ฌํญ)
๐ง next.config.mjs
์์
tsxCopy code
import createMDX from '@next/mdx';
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ['js', 'jsx', 'md', 'mdx', 'ts', 'tsx'],
experimental: {
appDir: true,
},
};
const withMDX = createMDX({
extension: /\.(md|mdx)$/,
options: {
// ํ์ํ ๊ฒฝ์ฐ MDX ์ต์
๋ฐ ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
},
});
export default withMDX(nextConfig);
pageExtensions
๋ถ๋ถ์md
,mdx
๋ฅผ ์ถ๊ฐํด์ค๋๋ค.withMDX
๋ฅผ ์ถ๊ฐํด์ค๋๋ค.
โ๏ธ ts.config.json
์ค์
jsonCopy code
{
"compilerOptions": {
// ํ์ํ ์ต์
์ถ๊ฐ
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx",
"**/*.md",
"**/*.mdx"
]
}
include
๋ถ๋ถ์md
ํ์ผ๊ณผmdx
ํ์ผ์ ์ถ๊ฐํด์ค๋๋ค.
๐ mdx-components.tsx
์์ฑ
mdx-components.tsx
ํ์ผ์ ์์ฑํ์ฌ ๊ฐ๋ณ ์ปค์คํ
์ค์ ์ด ๊ฐ๋ฅํฉ๋๋ค.
tsxCopy code
import type { MDXComponents } from "mdx/types";
export const HighlightedText = ({ children }: { children: React.ReactNode }) => {
return <span style={{ backgroundColor: "yellow" }}>{children}</span>;
};
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
...components,
h1: (props) => <h1 style={{ color: "blue" }} {...props} />,
HighlightedText,
};
}
๐ mdx-provider.tsx
์์ฑ
tsxCopy code
import { MDXProvider } from "@mdx-js/react";
import { useMDXComponents } from "./mdx-components";
export function MDXComponentsProvider({ children }: { children: React.ReactNode }) {
const components = useMDXComponents({});
return <MDXProvider components={components}>{children}</MDXProvider>;
}
provider
๋ .md
, .mdx
ํ์ผ์ ํ์ ์ปดํฌ๋ํธ๋ฅผ ์ฌ์ฉํ ์ ์๊ฒ ํด์ค๋๋ค.
๐ .md
๋๋ .mdx
ํ์ผ ์์ฑ
mdCopy code
# Welcome.mdx
This is a blog post written in **MDX**.
- List item 1
- List item 2
<HighlightedText> This text is highlighted in MDX! </HighlightedText>```python
print('hello')
๐ .tsx
ํ์ด์ง ์์ฑ
## ๐ ํ์ด์ง ์์ฑ
```tsx
"use client";
import Welcome from "@/markdown/welcome.mdx";
import Test from "@/markdown/test.md";
import { MDXComponentsProvider } from "@/mdx/mdx-provider";
export default function Page() {
return (
<MDXComponentsProvider>
<Welcome />
<Test />
</MDXComponentsProvider>
);
}
๐๏ธ ๋งํฌ๋ค์ด ์ฝ๋ ํ์ด๋ผ์ดํ ์์
- remark-gfm
yarn add remark-gfm
remark-gfm
์ ๋งํฌ๋ค์ด ํ์ผ์์ ํ๋ ๋ฆฌ์คํธ๋ฅผ ๋ ๋ค์ฑ๋กญ๊ฒ ํํํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ์
๋๋ค.
๐ง next.config.mjs
์์
import createMDX from "@next/mdx";
import rehypeHighlight from "rehype-highlight";
/** @type {import('next').NextConfig} */
const nextConfig = {
pageExtensions: ["js", "jsx", "md", "mdx", "ts", "tsx"],
experimental: {
appDir: true
}
};
const withMDX = createMDX({
extension: /\.(md|mdx)$/,
options: {
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeHighlight] // rehype ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ
}
});
export default withMDX(nextConfig);
remark-gfm
์ options
ํญ๋ชฉ์ ์ถ๊ฐ
๐ ์ฝ๋ ํ์ด๋ผ์ดํ ๋ฐฉ๋ฒ ์ ํ
๋ฐฉ๋ฒ 1: ๐๏ธ rehype-highlight & prismjs
์ค์น
yarn add rehype-highlight prismjs
globals.css
์ ์ถ๊ฐ
/* globals.css */
@import "prismjs/themes/prism.css";
next.config.mjs
์์
options: {
remarkPlugins: [remarkGfm],
rehypePlugins: [rehypeHighlight],
}
๋ฐฉ๋ฒ 2: ๐ผ๏ธ react-syntax-highlighter
์ค์น
yarn add react-syntax-highlighter
yarn add @types/react-syntax-highlighte
code-block
์ปดํฌ๋ํธ ์ ์
import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';
import { [ํ
๋ง์ ์๋ถ๋ถ] as theme } from 'react-syntax-highlighter/dist/esm/styles/prism';
interface CodeBlockProps {
language: string;
value: string;
}
export const CodeBlock = ({ language, value }: CodeBlockProps) => {
return (
<SyntaxHighlighter language={language} style={theme}>
{value}
</SyntaxHighlighter>
);
};
mdx-components.tsx
์์
import React from "react";
import type { MDXComponents } from "mdx/types";
import { CodeBlock } from "./code-block";
export const HighlightedText = ({
children
}: {
children: React.ReactNode;
}) => {
return <span style={{ backgroundColor: "yellow" }}>{children}</span>;
};
export function useMDXComponents(components: MDXComponents): MDXComponents {
return {
...components,
h1: (props) => <h1 style={{ color: "blue" }} {...props} />,
code: (props) => {
const { className, children } = props as any;
const match = /language-(\w+)/.exec(className || "");
return match ? (
<CodeBlock language={match[1]} value={String(children).trim()} />
) : (
<code {...props} />
);
},
HighlightedText
};
}
์ด ๊ณผ์ ์ ๊ฑฐ์น๋ฉด ์ฝ๋๊ฐ ๊น๋ํ๊ฒ ๋๋ค.
๋ฐ์ํ
'Stack > Next.js' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
Button์ผ๋ก Resizable ๊ตฌํํ๊ธฐ (2) | 2024.06.04 |
---|---|
Draggable ๊ตฌํํ๊ธฐ (0) | 2024.06.04 |
Next.js metadata ๋ค๋ฃจ๋ ๋ฐฉ์์ ๋ณ (1) | 2024.05.14 |
Next Image ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ (1) | 2024.05.14 |
MongoDB ์ Next.JS ์ฐ๊ฒฐํ๊ธฐ (0) | 2024.05.01 |