ブログをNext.jsで作り直した

2023-11-11#meta

およそ3年ぶりにホームページおよびブログを作り直した。今回はNext.jsで作ってみた。ソースコードはnaoty/homepageにある。

また、今回の変更によりブログはblog.naoty.devからnaoty.dev/posts/以下に移動することになったため、RSSフィードを登録している稀有な方は再度設定をお願いします。ページ下にリンクがあります。

ブログ自作史

せっかくなので、これまでのブログの自作史を振り返ってみたい。

バージョン期間フレームワーク記録
v12017 ~ 2018gulp304
v22018 ~ 2019Gatsby.js342
v32019 ~ 2020Nuxt.js384
v42020 ~ 2021Gatsby.js401
v52021 ~ 2023Ruby(フルスクラッチ)434
v62023 ~Next.js528

#metaをのぞいてみると、より詳細な記録が残っている。だいたい1年おきに当時興味のあったフレームワークを学ぶために作り直していたが、ここ2, 3年は使い慣れたRubyでフルスクラッチしたシステムで落ち着いていた。だけど、ここにきて今回興味のあったNext.jsを学ぶために作り直すことになった。

途中でブログサービスなどに投稿していた記事をインポートしたり、ドメインを移したり、リポジトリを分割したり統合したりしながら、今のブログに至る。

ブログというのはWebフロントエンドのフレームワークを学ぶためのお題として実益も兼ねていて気に入っていて、今後も何度も作り替えるんだろうなと思っている。

Next.js

ReactやNext.jsは以前から触っていたためだいたい理解していたが、Next.js v13.4で導入されたApp Routerであったり、最近のReactについてキャッチアップできていなかったことが今回ブログを作り直すきっかけとなった。ブログというシステムの性質上、Server Actionsなどカバーできない部分はあるものの、App RouterであったりRSCについて雰囲気はつかめた。

このブログは大半がサーバーサイドコンポーネントで実装されているものの、記事一覧ページはクエリパラメータによってフィルタリングするために一部クライアントコンポーネントで実装されている。ユーザーの目線ではまったく区別がつかないものの、基本的にはサーバーでHTMLを生成し、必要な部分だけクライアントで生成するようになったため、パフォーマンスやセキュリティ面で大きなアドバンテージがあり、Webフロントエンドフレームワークの大きな進化を感じられた。

Contentlayer

Next.jsでブログシステムを作るにあたって課題となったのは、記事データをNext.jsに取り込むために必要なグルーコードにあった。Next.js単体ではmarkdownファイルを更新したときにFast refreshしてくれないため、このままでは記事執筆エクスペリエンスもあまり良くなかった。

そんなときにContentlayerを発見し、今回採用することにした。Contentlayerは記事ファイルからNext.jsに取り込むためのグルーコードを型付きで自動生成しつつ、記事ファイルを監視して更新を自動的に反映してくれる。markdownのパースは内部的に後述するunifiedを使っているため、そのエコシステムをそのまま活用できるのも良い。

今回はローカルファイルをコンテンツとして扱う使い方をしたけど、どうやらNotionをコンテンツとして扱えるようにしたりNext.js以外のフレームワークにも対応していたりするらしく、コンテンツとフレームワークの間を埋める筋の良いツールだなと思った。

unified

unifiedはコンテンツをAST(抽象構文木)に変換し、ASTを加工し、ASTを別の形式に変換するためのインターフェイスを提供していて、そのインターフェイスを実装したさまざまなパッケージがエコシステムを構成している。gulpに発想が似ている。

Markdownはremark-parseによってmdastに変換され、mdastはremark-rehypeによってhastに変換され、hastはrehype-stringifyによってHTMLに変換される

図の通りremark-parseremark-rehyperehype-stringifyの3つのunifiedプラグインを使ってMarkdownをHTMLに変換している。mdastはMarkdownのASTで、hastはHTMLのASTを表している。

Markdownを直接HTMLに変換するのではなくASTを経由することで、ASTを加工する余地が生まれ、さまざまな変換処理をパイプラインに組み込むことができる。このブログでは上の3つのプラグインの他にremark-gfmを使ってGFM形式のmarkdownをサポートしたり、rehype-pretty-codeを使ってコードブロックにsyntax highlightを付与したりしている。

vercel

今回のブログはvercelにホスティングしている。Next.jsを開発している企業ということもあり、デプロイやカスタムドメインの設定が非常にスムーズにできており、Herokuを思い出させる。

今後

いろいろ調べている中でMDXというものを知り、新しいブログの可能性を感じている。MDXはmarkdownの中にReactコンポーネントを埋め込めるファイル形式で、JSXのmarkdown版ということになる。

markdown形式を維持することで、コンテンツを喪失することなく何度もブログシステムを作り直すことができた。mdx形式になるとそのコンテンツをサポートする選択肢が限定されるデメリットがある。

それでも尚、テキストや画像以外の表現方法ができるようになるし、動的なコンテンツも作れるようになるため、可能性に期待せざるをえない。個人的には将棋プレイヤーをブログに埋め込めるんじゃないかと思っており、試行錯誤してみたいと思っている。