Blog StarterにZenn Markdownを組み込む

Cover Image for Blog StarterにZenn Markdownを組み込む
記事制作日:
web開発

目標

Blog Starterを使ってZenn Markdownが使える個人ブログを作成する

インストール

node.jsのインストール

node.jsのインストラーに従うだけ

blog-starterの追加

設置したいフォルダーを作成して、そのフォルダーに移動してから以下のコマンドを実行する
今回使用したlatestのバージョンは15.0.2

npx create-next-app@latest --example blog-starter .

Docker設定

Docker Desktopのインストール

Docker Desktopのインストーラーに従うだけ

Dockerfileの作成

Dockerfile
# Node.js 22がLTSなので、ベースイメージに指定
FROM node:22
# アプリケーション用の作業ディレクトリを作成
WORKDIR /app
# 依存関係をインストール
COPY package.json package-lock.json ./
RUN npm install
# ソースコードをコンテナ内にコピー
COPY . .
# 開発用サーバーを起動するポートを公開
EXPOSE 3000
# Next.js 開発サーバーをデフォルトで起動
CMD ["npm", "run", "dev"]

docker-compose.ymlの作成

docker-compose.yml
version: "3.8"
services:
  blog:
    build: .
    ports:
      - "3000:3000"
    volumes:
      - .:/app
      - /app/node_modules
    stdin_open: true
    tty: true

.dockerignoreの作成

.dockerignore
node_modules
npm-debug.log
.dockerignore

dockerのビルド、起動

docker compose build
docker compose up

起動確認

http://localhost:3000/
にアクセスして、サンプルページが表示されれば無事に起動している

Zenn Markdown, CSSの導入

パッケージの追加

2024/12/30現在の最新バージョンは0.1.158だったので、package.jsonに追加

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

package.jsonを変更したので、一度ビルドする

docker compose build

Zenn Markdown, CSS対応のためのコードの変更

markdownをhtmlに変換する関数をzenn-markdown-htmlに変更

src/lib/markdownToHtml.ts
- import { remark } from 'remark'
- import html from 'remark-html'
+ import m2h from "zenn-markdown-html";

export default async function markdownToHtml(markdown: string) {
- const result = await remark().use(html).process(markdown)
- return result.toString()
+ return m2h(markdown)
}

zenn cssを読み込むように追加

src/app/layout.tsx
+ import 'zenn-content-css'

class名にzenn cssが動くようにzncを追加

src/app/_components/post-body.tsx
- <div className="max-w-2xl mx-auto">
+ <div className="max-w-2xl mx-auto znc">

Next.js 13からapp routerでは、サーバーコンポーネントでuseEffectを使えなくなった。
なので、クライアントコンポーネントとして切り分けてインポートする必要がある。
クライアントコンポーネントとしてsrc/app/_components/zenn-embed.tsxを作成する。

src/app/_components/zenn-embed.tsx
"use client";

import 'zenn-content-css';
import { useEffect } from "react";

export default function ZennEmbed(props: { html: string }) {
  useEffect(() => {
    import('zenn-embed-elements');
  }, []);

  return (
    <div
      className="znc"
      dangerouslySetInnerHTML={{
        __html: props.html, 
      }}
    />
  );
}

ZennEmbedを使うために記事のページを変更する。

src/app/posts/[slug]/page.tsx
- import markdownToHtml from "@/lib/markdownToHtml";
+ import markdownToHtml from "zenn-markdown-html";
+ import ZennEmbed from "@/app/_components/zenn-embed";
...
- const content = await markdownToHtml(post.content || '')
+ const content = await markdownToHtml(post.content || '', {
+   embedOrigin: "https://embed.zenn.studio",
+ })

  return (
    <main>
      <Container>
        <Header />
+       <script src="https://embed.zenn.studio/js/listen-embed-event.js"></script>
        <article className="mb-16">
          ...
-         <PostBody content={content} />
+         <ZennEmbed html={content} />
        </article>
      </Container>
    </main>
  );
}
...

以上でblog-starterのpostでZenn Markdownが使えるようになる。
良い個人ブログライフを!

参考記事

Zenn Editor - GitHub
エンジニアなら自分でブログを作れ!③Markdownのカスタマイズ編
Next.js × microCMSでZennのマークダウンを表示するブログの作り方
Pages RouterからApp Routerへ移行した話 Next.js v13