ホームページ > ウェブフロントエンド > CSSチュートリアル > next.jsの責任あるマークダウン

next.jsの責任あるマークダウン

Joseph Gordon-Levitt
リリース: 2025-03-21 10:57:11
オリジナル
822 人が閲覧しました

next.jsの責任あるマークダウン

マークダウンは確かに素晴らしいフォーマットです。誰もが迅速に学ぶことができるプレーンテキストに十分近く、それは解析するのに十分な十分に構造化されており、最終的にあなたが望む形式に変換されます。

ただし、マークダウンの解析、処理、強化、および変換にはコードが必要です。クライアントにこのすべてのコードを展開すると、価格があります。それ自体はそれほど大きくはありませんが、それでもマークダウンを処理するためだけに使用されているのは数十KBのコードであり、他の目的はありません。

この記事では、Unified/Learm Ecosystemを使用して、Next.jsアプリケーションでクライアントからマークダウンを締め出す方法について説明します(使用する名前はわかりませんが、これは混乱しすぎます)。

主なアイデア

アイデアは、ビルドプロセス中にこれを行うには、next.jsのgetStaticProps関数のMarkDownのみを使用することです(Vercelのインクリメンタルビルドを使用する場合、次のサーバーレス機能で行われます)が、クライアント側では決して使用されません。 getServerSidePropsも大丈夫だと思いますが、 getStaticProps一般的なユースケースになる可能性が高いと思います。

これにより、マークダウンコンテンツの解析と処理によって生成されたAST(抽象的構文ツリー、つまりコンテンツを記述する大きなネストされたオブジェクト)によって生成され、クライアントはASTをReactコンポーネントにレンダリングする責任があります。

getStaticPropsでHTMLとしてMarkDownを直接レンダリングして、 dangerouslySetInnerHtml setinnerhtmlでレンダリングするように戻すことさえできますが、私たちはそのような人ではありません。安全性は重要です。また、マークダウンを純粋な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/Learm Ecosystemを使用します。私たちは統一された発言権をインストールする必要があります、それだけです。マークダウン自体を解析することは比較的簡単です:

 「unified」から{unified}をインポートします
「aremerparse」から発言をインポートする

const parsemarkdown = content => unified()。use(aremparse).parse(content)

デフォルトのパーセマークダウンをエクスポートします
ログイン後にコピー

さて、私が理解するのに長い時間がかかったのは、なぜ驚異的なプラグインやシーケルスラグのような私の余分なプラグインがこのように機能しないのかということです。これは、Unified .parse(..)メソッドがプラグインを使用してASTを処理しないためです。名前が示すように、それはマークダウン文字列のコンテンツをツリーに解析するだけです。

Unifiedをプラグインに適用したい場合は、「実行中」フェーズと呼ばれるものを実行するためにUnifiedが必要です。通常、これは.process(..)メソッドの代わりに.parse(..)メソッドを使用して行われます。残念ながら、 .process(..)はマークダウンを解析してプラグインを適用するだけでなく、ASTを別の形式に描きます(たとえば、derme-htmlを介してHTMLを使用するか、remark-reactを介してJSXを使用します)。そして、ASTを維持したいので、それは私たちが望むものではなく、プラグインによって処理された後です。

 <code>| ........................ process ........................... | | .......... parse ... | ... run ... | ... stringify ..........| -------- ----------输入->- | 解析器| ->- 语法树->- | 编译器| ->- 输出-------- | ---------- X | -------------- | 变换器| --------------</code>
ログイン後にコピー

したがって、私たちがする必要があるのは、解析フェーズと実行フェーズを実行するだけではありません。 Unifiedは、これら3つの段階のうち2つを実行する方法を提供しませんが、各段階に個別の方法を提供するため、手動で実行できます。

 「unified」から{unified}をインポートします
「aremerparse」から発言をインポートする
「発言権」からの発言プリズムをインポートする

const parsemarkdown = content => {
  const engine = unified()。use(aremparse).use(aremprism)
  const ast = engine.parse(content)

  // Unified's * Process *には、解析、実行、および弦の3つの異なる段階が含まれています。 「.process(..)」を呼び出すことができないように、astを維持したいので、描画段階を通過したくありません。ただし、プラグイン(したがってプリズム)が実行フェーズ中に実行されるため、 `.Parse(..)`を呼び出すだけでは不十分です。したがって、実行フェーズを手動で呼び出す必要があります(簡単に、同期して)。
  //参照:https://github.com/unifiedjs/unified#description
  return engine.runsync(ast)
}
ログイン後にコピー

見て!マークダウンを構文ツリーに解析しました。次に、そのツリーでプラグインを実行します(簡単にするために同期して行われますが、 .run(..)を使用して非同期に行うことができます)。ただし、ツリーをHTMLやJSXなどの他の構文に変換しませんでした。私たちはレンダリングでそれを自分で行うことができます。

レンダリングマークダウン

クールな木が準備が整ったので、意図したとおりにレンダリングすることができます。ツリーをastプロパティとして使用し、ReactコンポーネントでレンダリングするMarkdownRendererコンポーネントを作成しましょう。

 const getComponent = node => {
  switch(node.type){
    ケース「ルート」:
      return({children})=>  {children} >

    ケース「段落」:
      return({children})=><p> {子供たち}</p>

    ケース「強調」:
      return({children})=> <em>{children}</em>

    ケース「見出し」:
      return({children、dept = 2})=> {
        const heading = `h $ {depth}`
        戻る<heading>{子供たち}</heading>
      }

    ケース「テキスト」:
      return({value})=>  {value} >

    / *ここですべてのタイプを処理します... */

    デフォルト:
      console.log(「未処理ノードタイプ」、ノード)
      return({children})=>  {children} >
  }
}

const node =({node})=> {
  const Component = getComponent(ノード)
  const {children} = node

  子供を返しますか?
    <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.hchildren [0] .data.hchildren [0] .data.hchildren [0] .data.hname(from getstaticprops in '/')。原因:未定義をJSONに連続化することはできません。 nullを使用するか、この値を省略してください。

これは、ASTに未定義の値を持つキーが含まれているために起こります。これは、JSONに安全にシリアル化できるものではありません。次に、解決策を提供します。値を完全に省略するか、多かれ少なかれ必要な場合はnullに置き換えることができます。

ただし、各パスを手動で修正することはないため、そのASTを再帰的に横断してクリーンアップする必要があります。これは、発言権(コードブロック構文の強調表示を可能にするプラグイン)を使用するときに起こることがわかりました。プラグインは[data]オブジェクトをノードに追加します。

私たちにできることは、ASTを返す前にこれらのノードをクリーンアップするために繰り返します。

 const cleannode = node => {
  if(node.value === undefined)delete node.value
  if(node.tagname === undefined)delete node.tagname
  if(node.data){
    node.data.hnameを削除します
    node.data.hchildrenを削除します
    node.data.hpropertiesを削除します
  }

  if(node.children)node.children.foreach(cleannode)

  ノードを返します
}

const parsemarkdown = content => {
  const engine = unified()。use(aremparse).use(aremprism)
  const ast = engine.parse(content)
  const processedast = engine.runsync(ast)

  cleannode(processedast)

  Processedastを返します
}
ログイン後にコピー

最後にできることは、各ノードに存在するpositionオブジェクトを削除することです。これは、マークダウン文字列の元の位置を保持します。大きなオブジェクトではありません(キーは2つしかありません)が、ツリーが大きくなるとすぐに蓄積します。

 const cleannode = node => {
  node.positionを削除します
  // ...その他のクリーニングロジック}
ログイン後にコピー

要約します

それでおしまい!マークダウン処理をなんとか制限/サーバーサイドコードに制限することができたため、ブラウザに不必要なマークダウンランタイムを送信することはありませんでした。データツリーをクライアントに渡し、それを繰り返して、必要な任意のReactコンポーネントに変換できます。

これが役立つことを願っています。 :)

以上がnext.jsの責任あるマークダウンの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
人気のチュートリアル
詳細>
関連するチュートリアル
人気のおすすめ
最新のコース
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート