gAmuLog.
がむログ

Next.js App RouterにおけるZenn記法Markdown→HTML変換処理

投稿日:
Cover Image for Next.js App RouterにおけるZenn記法Markdown→HTML変換処理

まえがき

この技術ブログは、Next.js の Blog Starter Kit を用いて開発されている。記事内容ページを作成するにあたって、Zenn 記法の markdown を HTML に変換し、Zenn 風の CSS をつけることができるらしいので、その設定を行った。

https://vercel.com/templates/next.js/blog-starter-kit

困ったこと(読まなくても良い)

様々な方の記事を読みつつ、Zenn 記法 markdown→HTML 変換処理を調べていたのだが、自分が見た中だと記事がすべてPages Routerでの実装方法になっていて、なかなか上手くできない。App RouterPages Routerではディレクトリ構造も違うし、サーバーコンポーネントとクライアントコンポーネントも意識しながら実装しないといけない。いろいろ記事や公式ドキュメントを見たが、useEffectを使う実装が基本らしく、SSG のブログ本文にuseEffectで変換処理を行うのは SEO 的に大丈夫なのかとか、そもそもApp Routerでのプロジェクトではどの部分にその実装を行えばいいのかとか、とにかく頭に「?」をいっぱい出しながら試行錯誤した。以下参考にした記事(や issue や公式ドキュメント)である。

https://zenn.dev/team_zenn/articles/intro-zenn-markdown
https://kenpos.dev/next.jsでブログを作りなおすまずはzennスタイルを適用してみた/#zennライクなmarkdown記法を扱えるようにする
https://github.com/zenn-dev/zenn-editor/issues/293
https://www.npmjs.com/package/zenn-markdown-html?activeTab=readme

どのコード例もPages Routerで説明されていて、そもそもApp Router以降の Next.js しか使ったことがない自分としてはこれらの実装をApp Routerでどのように対応させればいいのかが難しかった...

実装

なんとか実装できた...(KaTeX 除く)

パッケージ

package.json
  "dependencies": {
    "zenn-content-css": "^0.1.131",
    "zenn-markdown-html": "^0.1.131",
    "zenn-embed-elements": "^0.1.131"
  },

/[slug]/page.tsx

/[slug]/page.tsx
...
const content = markdownToHtml(post.content || "", {
    embedOrigin: "https://embed.zenn.studio",
  }); // zenn記法マークダウンをHTMLに変換する処理

  return (
    <main>
      <PostPageHeader />
      <article className="my-32 px-16 znc"> // znc 付与でCSSを反映させる
        <Script
          src="https://embed.zenn.studio/js/listen-embed-event.js"
          strategy="afterInteractive"
        /> // インタラクティブになった後に実行される、埋め込みコンテンツ(リンクカードなど)用の処理

        <PostTitle>{post.title}</PostTitle>
        <div className="flex mx-16 justify-between">
          <PostBody
            title={post.title}
            date={post.date}
            tags={post.tags}
            coverImage={post.coverImage}
            content={content}
          />
          <Sidebar
            relatedPosts={relatedPosts}
            recommendedPosts={recommendedPosts}
          />
        </div>
      </article>
    </main>
  );
}

実装が終わってみたらめちゃめちゃ単純だった。ただ、数式変換処理は実装していないので、KaTeX のみ利用することができない。ここにレポート提出でもしない限り使わないかなぁ

参考
https://github.com/zenn-dev/zenn-editor#ご自身のwebサイトで使う場合