2024년 12월 27일
lib/rehypeExtractingHeadings.ts 전체코드
import { Root } from 'hast';
import { Element } from 'hast';
import { visit } from 'unist-util-visit';
export interface Heading {
id: number;
text: string;
level: number;
}
export default function rehypeExtractHeadings(headings: Heading[]) {
return (tree: Root) => {
visit(tree, 'element', (node: Element) => {
if (['h1', 'h2', 'h3'].includes(node.tagName)) {
const level = Number(node.tagName[1]);
const text = (node.children || [])
.filter((child) => child.type === 'text')
.map((child) => child.value)
.join('');
const id = tree.children.indexOf(node);
headings.push({ id, text, level });
node.properties.id = id;
}
});
};
}
Heading 인터페이스
export interface Heading {
id: number;
text: string;
level: number;
}
level의 경우 h1은 1, h2는 2가 되는 방식
rehypeExtranctHeadings
HTML AST(Abstract Syntax Tree)을 순회하면서 헤더 정보를 추출
export default function rehypeExtractHeadings(headings: Heading[]) {
return (tree: Root) => { ... };
}
인수인 headings 배열에 추출된 헤더 데이터 저장
tree를 출력하면 다음과 같이 출력됨
각 노드의 tagName에 추출하고자 하는 h1, h2, h3가 포함되어 있으면 이를 추출하면 될 듯
visit(tree, 'element', (node: Element) => {
if (['h1', 'h2', 'h3'].includes(node.tagName)) {
...
}
});
tree
: MDX가 HTML AST로 변환된 트리 구조.'element'
: HTML 태그(<h1>
, <h2>
등)를 대상으로 처리.node
: 현재 순회 중인 AST 노드.h1, h2, h3에 node.tagName이 포함된 경우만을 처리
const level = Number(node.tagName[1]);
const text = (node.children || [])
.filter((child) => child.type === 'text')
.map((child) => child.value)
.join('');
const id = tree.children.indexOf(node);
headings.push({ id, text, level });
node.properties.id = id;
level은 tagName(h1, h2, h3)의 1,2,3 추출
text는 해당 노드의 children 내부에서 text인 child로 필터링 후 value 추출
id는 tree 배열에서 해당 노드의 인덱스
headings 배열에 해당 heading 넣고, 해당 노드의 아이디 갱신
const headings: Heading[] = [];
const mdxContent = await serialize(content, {
mdxOptions: {
rehypePlugins: [[rehypeExtractHeadings, headings]],
},
});
headings 저장할 배열 만들고 인수로 전달
배열의 첫 번째 요소는 플러그인 함수 이름, 두 번째 요소는 해당 플러그인에 전달할 인수.
serialize로 content 가져올때 mdxOptions 주는 방식 !
mdxRender 컴포넌트 내부의 mdxRemote에 mdxOptions을 주는 방식과
위처럼 콘텐츠를 가져올때 mdxOptions를 주는 방식 두가지가 존재
첫번째는 콘텐츠 렌더링 직전에 옵션을 적용하는 것으로, 서버가 아닌 클라이언트에서만 필요한 변환에 적합.
두번째는 mdx 콘텐츠가 AST로 변환될때 옵션을 적용하는 것으로, 서버에서 데이터를 가공 후 클라이언트에 전달하는 경우 적합함.
원래는 상세페이지의 전체 컴포넌트에 prose mx-auto가 들어가있는 상황이었는데 prose를 쓰면 전체 너비가 제한되는 상황이 있었고, 이 제한된 너비에 본문과 toc를 모두 넣기에는 무리가 있었다.
tailwilnd.config.js 코드를 수정하여 prose가 제한하는 너비의 상한을 변경하였다.