λ°μν
π 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 ꡬννκΈ° (0) | 2024.06.04 |
---|---|
Draggable ꡬννκΈ° (0) | 2024.06.04 |
Next.js metadata λ€λ£¨λ λ°©μμ λ³ (0) | 2024.05.14 |
Next Image μ¬μ©νλ λ°©λ² (0) | 2024.05.14 |
MongoDB μ Next.JS μ°κ²°νκΈ° (0) | 2024.05.01 |