🚄

Next.js (App Router) とTailwind CSSでマークダウンブログを作ってみた

2023/09/20に公開

皆さんこんにちは。Sandyマンです!

この度、私のブログ「Sandyマンのブログ」をHugoからNext.js (App Router)に移行しました🎉

今回はそのブログの実装や詳細について書いていこうと思います!

使用技術

  • Next.js 13 (App Router)
  • TypeScript
  • Tailwind CSS
  • Vercel
  • Google Analytics (GA4)

だいたいこんな感じです。

Next.jsかGatsbyか

React系のフレームワークを使うのは決めていたのですが、Next.jsとGatsbyの2択でかなり迷いました。ですが結局はGatsbyの何でもかんでもプラグイン方式があまり好きじゃなかったので、Next.jsを選択しました。

デプロイ先

デプロイ先はNext.jsの開発元で相性抜群なVercelを選択しました。とても便利で助かってます。今のところ広告など収益化はしてないので、Hobbyプランで全然対応できています。

記事の管理

記事の管理は、MicroCMSやContentfulなどのヘッドレスCMSの使用も考えたのですが、Gitで管理したかったのでマークダウンファイルを読み込む感じにしてます。

ただ、ブログのソースコードと記事ファイルは分けておきたかったので、別リポジトリにしてsubmoduleで読み込むようにしています。VercelのDeploy Hooksなどを使って、記事リポジトリが更新されたら自動でビルドがかかるようにしました。

実装

実装は基本的にNext.jsの公式チュートリアルを参考にしました。Pages Routerを使ったチュートリアルですが、App Routerでもとても参考になります。

マークダウンの処理

マークダウンの処理にはunifiedを使用しています。拡張は以下のようなものを導入しました。

"@jsdevtools/rehype-toc": "^3.0.2",
"rehype-prism-plus": "^1.6.3",
"rehype-react": "^7.2.0",
"rehype-slug": "^6.0.0",
"remark-gfm": "^3.0.1",
"remark-parse": "^10.0.2",
"remark-rehype": "^10.1.0",

rehype-prism-plusでコードハイライト、rehype-reactで要素のカスタマイズ、rehype-tocとrehype-slugは目次を実装するために導入しています。

コードはこんな感じになりました。

const markdownToReact = async (markdown: string, id: string) => {
    const result = (
        await unified()
            .use(remarkParse)
            .use(remarkGfm)
            .use(remarkRehype)
            .use(rehypePrism)
            .use(rehypeSlug)
            .use(rehypeToc, {
                headings: ["h2", "h3"],
                cssClasses: {
                    toc: "sm-toc",
                    link: "sm-toc-link",
                    listItem: "sm-toc-list-item",
                    list: "sm-toc-list",
                },
            })
            .use(rehypeReact, {
                createElement,
                Fragment,
                components: {
                    img: Postimg(id),
                },
            })
            .process(markdown)
    ).result;
    return result;
};

SSG(Static Site Generation)化する

何もしないとSSRの動的なサイトになってしまうので、SSGに対応させます。具体的には以下のようなことをしました。

  • next.config.jsにoutput: "export"を追加
  • /app/posts/[slug]/page.tsxみたいな動的ルーティングな感じのページにgenerateStaticParamsを追加(getStaticPathsみたいなやつ)

generateStaticParamsはこんな感じのやつです。

export const generateStaticParams = () => {
    return allPostsData.map((post) => {
        return {
            slug: post.id,
        };
    });
};

SEO対策

一応ブログなのでSEO対策もしました。

メタデータは、各ページやlayout.tsxgenerateMetadatametadataを使うと設定することができます。こんな感じです。

metadataの例
export const metadata: Metadata = {
    metadataBase: new URL("https://www.sandyman.dev"),
    title: "Sandyマンのブログ",
    description: "JavaScriptやLinuxなどいろいろ記事書いてます",
    openGraph: {
        // 省略
    },
    twitter: {
        // 省略
    }
}

generateMetadatametadataに関してはこのあたりが参考になりました。
https://zenn.dev/ikenohi/scraps/654b7ecff80c30
https://nextjs.org/docs/app/api-reference/functions/generate-metadata#the-metadata-object

感想

App Routerを使ってみて、今までより直感的にできる感じがしてとても良いなと思いました。SEOの設定などが簡単にできるのもとても便利ですね。ただ、しっかりServer Componentsなどについて理解しないと使いこなせないなと思いました。(当たり前か...)

まとめ

こんな感じでブログを作ってみました。皆さんもぜひApp Router、触ってみてください!もし記事の間違いなど訂正があれば教えてください🙏それでは!

作ったブログはこちらから↓
https://www.sandyman.dev

Discussion