Markdown은 실제로 훌륭한 형식입니다. 누구나 빠르게 배울 수있는 평범한 텍스트에 가깝고, 구문 분석 할 수있을 정도로 잘 구성되어 있으며 결국 원하는 형식으로 변환됩니다.
그러나 마크 다운을 구문 분석, 처리, 강화 및 변환하려면 코드가 필요합니다. 이 모든 코드를 클라이언트에 배포하는 것은 가격으로 제공됩니다. 그 자체로는 크지 않지만 여전히 Markdown과 다른 목적을 처리하는 데 사용되는 수십 개의 KB 코드입니다.
이 기사에서는 Unified/Warick 생태계를 사용하여 Next.js 응용 프로그램에서 클라이언트에서 Markdown을 유지하는 방법을 설명하겠습니다 (실제로 어떤 이름을 사용할 것인지, 너무 혼란 스럽습니다).
아이디어는 빌드 프로세스 중에 다음에 getStaticProps
함수에서 Markdown 만 사용하여 빌드 프로세스 중에이를 수행하는 것입니다 (Vercel의 증분 빌드를 사용하는 경우 다음 서버리스 기능에서 수행됩니다). 나는 getServerSideProps
도 괜찮다고 생각하지만 getStaticProps
일반적인 사용 사례 일 가능성이 높다고 생각합니다.
이것은 마크 다운 컨텐츠를 구문 분석 및 처리하여 생성 된 AST를 반환하며 ( 추상 구문 트리 , 즉 콘텐츠를 설명하는 큰 중첩 객체) 클라이언트는 AST를 반응 구성 요소로 만 렌더링 할 책임이 있습니다.
getStaticProps
에서 직접 HTML로 Markdown을 렌더링하여 dangerouslySetInnerHtml
로 렌더링하기 위해 반품 할 수도 있지만, 그런 종류의 사람들은 아닙니다. 안전이 중요합니다. 또한 순수한 HTML로 렌더링하는 대신 자체 구성 요소로 원하는 방식으로 마크 다운을 렌더링하는 유연성. 진심으로, 친구, 그렇게하지 마십시오. ?
내보내기 const getstaticProps = async () => { // CMS 등과 같은 어딘가에서 마크 다운 컨텐츠를 얻습니다. 이 기사에 관한 한, 이것은 중요하지 않습니다. 파일에서 읽을 수도 있습니다. Const Markdown = Await getMarkdownContentFromsomewhere () const ast = parsemarkdown (Markdown) return {props : {ast}} } const page = props => { // 여기에는 일반적으로 레이아웃 등이 포함되지만 단순성을 위해 여기에서 생략됩니다. 반품<markdownrenderer ast="{props.ast}"></markdownrenderer> } 기본 페이지 내보내기
우리는 통합/비고 생태계를 사용할 것입니다. 우리는 통합 및 비고를 설치해야합니다. 자체를 구문 분석하는 것은 비교적 간단합니다.
'Unified'에서 {Unified} 가져 오기 '비고 양식'에서 warticparse 가져 오기 const parsemarkdown = content => unified (). 내보내기 기본 파시 마크 다운
이제 이해하는 데 오랜 시간이 걸렸던 것은 비고 프리즘이나 비고 슬러그와 같은 추가 플러그인이 이와 같이 작동하지 않는 이유입니다. Unified .parse(..)
메소드가 플러그인을 사용하여 AST를 처리하지 않기 때문입니다. 이름에서 알 수 있듯이 Markdown 문자열 내용을 트리에만 구문 분석합니다.
통합이 플러그인을 적용하기를 원한다면, 우리는 그들이 "실행"단계를 거치기 위해 통합해야합니다. 일반적으로 이것은 .process(..)
메소드 대신 .parse(..)
메소드를 사용하여 수행됩니다. 불행히도, .process(..)
Markdown을 구문 분석하고 플러그인을 적용 할뿐만 아니라 AST를 다른 형식 (예 : warick-html을 통해 html 사용 또는 비고 리아크를 통해 JSX를 사용하는 것)을 적용합니다. 그리고 그것은 우리가 AST를 유지하기를 원하기 때문에 우리가 원하는 것이 아니라 플러그인으로 처리 한 후에는 우리가 원하는 것이 아닙니다.
<code>| ........................ process ........................... | | .......... parse ... | ... run ... | ... stringify ..........| -------- ----------输入->- | 解析器| ->- 语法树->- | 编译器| ->- 输出-------- | ---------- X | -------------- | 变换器| --------------</code>
따라서, 우리가해야 할 일은 구문 분석 및 런 단계를 실행하지만 문자열화 단계는 아닙니다. Unified는이 세 단계 중 두 단계를 실행하는 방법을 제공하지 않지만 각 단계마다 별도의 방법을 제공하여 수동으로 수행 할 수 있습니다.
'Unified'에서 {Unified} 가져 오기 '비고 양식'에서 warticparse 가져 오기 '비고-프리즘'에서 공시 수입 const parsemarkdown = content => { const 엔진 = unified (). use (warticparse) .use (warticprism) const ast = engine.parse (콘텐츠) // Unified의 * process *에는 구문 분석, 실행 및 문자열이있는 세 가지 단계가 포함됩니다. 우리는`.process (..)`을 호출 할 수 없도록 ast를 유지하기를 원하기 때문에 문자열 화 단계를 거치고 싶지 않습니다. 그러나 플러그인 (및 프리즘)이 실행 단계에서 실행되기 때문에`.parse (..)`호출은 충분하지 않습니다. 따라서 실행 단계를 수동으로 호출해야합니다 (단순성을 위해 동기식). // 참조 : https://github.com/unifiedjs/unified#description return Engine.RUNSYNC (AST) }
바라보다! 우리는 구문 트리에 Markdown을 파싱했습니다. 그런 다음 해당 트리에서 플러그인을 실행합니다 (단순성을 위해 동기식으로 수행되지만 .run(..)
사용하여 비동기 적으로 수행 할 수 있습니다). 그러나 트리를 HTML 또는 JSX와 같은 다른 구문으로 변환하지 않았습니다. 우리는 렌더링에 스스로 할 수 있습니다.
이제 우리는 시원한 나무를 준비 했으므로 의도 한대로 렌더링 할 수 있습니다. 트리를 ast
속성으로 가져 와서 React 구성 요소로 렌더링하는 MarkdownRenderer
구성 요소를 만들어 봅시다.
const getComponent = node => { 스위치 (node.type) { 케이스 '루트': return ({children}) => {children} > 사례 '단락': return ({children}) =><p> {어린이들}</p> 사례 '강조': return ({children}) => <em>{children}</em> 케이스 '제목': return ({children, depth = 2}) => { const aiding =`h $ {깊이}` 반품<heading> {어린이들}</heading> } 사례 '텍스트': return ({value}) => {value} > / * 여기에서 모든 유형을 처리합니다 ... */ 기본: Console.log ( '처리되지 않은 노드 유형', 노드) return ({children}) => {children} > } } const node = ({node}) => { const 구성 요소 = getComponent (노드) const {children} = 노드 아이들? <component> {children.map ((child, index) => ( <node key="{index}" node="{child}"></node> ))} </component> ) : ( <component></component> )) } const MarkdownRenderer = ({ast}) =><node node="{ast}"></node> 내보내기 기본 React.Memo (MarkdownRenderer)
렌더러의 논리의 대부분은 Node
구성 요소에 있습니다. AST 노드의 type
키를 기반으로 렌더링 할 내용을 찾은 다음 각 유형의 getComponent
를 처리합니다. 그런 다음 렌더링합니다. 노드에 어린이가 있으면 재귀 적으로 하위 노드로 들어가면 구성 요소를 최종 잎 노드로 만듭니다.
사용중인 비고 플러그인에 따라 페이지를 렌더링하려고 할 때 다음과 같은 문제가 발생할 수 있습니다.
오류 : .Content [0] .Content.Children [3] .Data.Hchildren [0] .Data.hildren [0] .data.hildren [0] .data.hchildren [0] .Data.Hname ( '/'의 GetStaticProps에서). 원인 : 정의되지 않은 것은 JSON으로 직렬화 할 수 없습니다. NULL을 사용 하거나이 값을 생략하십시오.
이것은 우리의 AST에 정의되지 않은 값을 가진 키가 포함되어 있기 때문에 JSON에게 안전하게 직렬화 할 수있는 것이 아닙니다. 다음으로 솔루션을 제공합니다. 값을 모두 생략하거나 필요하면 NULL로 교체 할 수 있습니다.
그러나 각 경로를 수동으로 고정하지 않으므로 AST를 재귀 적으로 가로 질러 청소해야합니다. The Nark-Prism (코드 블록 구문 강조 표시를 가능하게하는 플러그인)을 사용할 때 이런 일이 발생했습니다. 플러그인은 노드에 [data]
객체를 추가합니다.
우리가 할 수있는 것은 AST를 반환하기 전에 이러한 노드를 정리하기 위해 반복하는 것입니다.
const cleannode = node => { if (node.value === 정의되지 않은) node.value를 삭제합니다 if (node.tagname === undefined) node.tagname을 삭제합니다 if (node.data) { node.data.hname을 삭제합니다 node.data.hildren을 삭제합니다 node.data.hproperties를 삭제합니다 } if (node.children) node.children.foreach (cleannode) 반환 노드 } const parsemarkdown = content => { const 엔진 = unified (). use (warticparse) .use (warticprism) const ast = engine.parse (콘텐츠) const processedast = engine.runsync (AST) 정화 노드 (Processedast) 반환 가공 }
우리가 할 수있는 마지막 일은 각 노드에 존재하는 position
객체를 삭제하는데, 이는 Markdown 문자열의 원래 위치를 유지하는 것입니다. 큰 물체는 아니지만 (두 개의 키만 있습니다) 나무가 커지면 빠르게 축적됩니다.
const cleannode = node => { Node.Position을 삭제합니다 // ... 기타 청소 논리}
그게 다야! 우리는 마크 다운 처리를 빌드/서버 사이드 코드로 제한 했으므로 불필요한 마크 다운 런타임을 브라우저로 보내지 않아 비용이 불필요하게 증가합니다. 우리는 데이터 트리를 클라이언트에게 전달하고 그것을 반복하여 원하는 반응 구성 요소로 변환 할 수 있습니다.
이것이 도움이되기를 바랍니다. :)
위 내용은 다음에 책임 마크 다운의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!