Honai's Blog

Markdownで記事を書けるブログをNext.jsで作った話

2019/04/07

こんにちは。ほないです。

はてなブログに 1 つだけ記事を投稿していましたが、 以前から自前のブログを作ってみたいと思っていました。 春休み最後の日に何とか形になったので、初投稿がてらまとめておきます。

目次

  • 仕様
  • Next.js について
  • ZEIT Now について
  • Markdown-it と katex について
  • まとめ
  • 参考サイト

仕様

Next.js を利用しました。通常のページ遷移は SPA ですが、静的 Export 的なことをやっているので ブラウザの JavaScript がオフでもレンダリングできます(検索エンジンもクロールできます)。

デプロイはNowというサービスを使っています。 Zeit という会社のサービスですが、Next.js をメンテナンスしている会社で、Next との親和性が高いです(後述)。

記事は Markdown ファイルで書きます(パーサーは markdown-it)。ビルド時にスクリプトを走らせ記事一覧を作成してます。

katex を利用した数式のレンダリングに対応しており、記事内で tex 形式で数式を書くことができます。

Next.js について

Next.js

React だけだと、ルーティングや SSR/静的化などを本格的にやろうとすると結構大変になってきますが、 Next はそういう部分を使いやすくしてくれるライブラリです。

ルーティングが便利

例えば React でだけで、 //about という 2 つのページを作って切り替えたいと思うと、 IndexコンポーネントとAboutコンポーネントを作って

<BrouserRouter>
  <Route path='/' component={Index}>
  <Route path='/about' component={About}>
</BrouserRouter>

みたいなことをやるんですね。

これが Next だと、pages というフォルダの中に index.jsabout.js を作って、 それぞれコンポーネントを export するだけです。共通のヘッダーとかを設定するのも簡単です。

SSR 対応/静的化が簡単

React などで普通にアプリを作ると、リロードしても正しいページが表示されるようにするのに苦労しますよね。 そのあたりの処理も Next.js はいい感じにしてくれます。 これは Next.js そのものではなくサーバー環境などにもよりますが、 例えばクエリなしのルーティングなら何もしなくてもリロードに対応します。 また後述の Now を使えば動的なルーティングも Node サーバーの設定なしで行えます。

静的サイトとしてエクスポートする機能も標準でついていて、 Github Pages のような Static Hosting で公開するのも簡単です。

ZEIT Now について

Now CLI

サーバーやクラウドの面倒なところを一切考えなくていい、 初心者にとっては非常にありがたい SaaS です (といっても今回の私のブログは静的なので、Github Pages でもホストできないことはないです)。 詳しくはチュートリアルを見ていただきたいですが、 設定を数行書いて now の 3 文字でデプロイできます。

しかもデプロイごとに プロジェクト名.ランダム.now.sh という形式で個別の URL が発行され、最新のものに プロジェクト名.ユーザー名.now.sh というエイリアスが自動で貼られます。 つまり、開発/ステージング/本番環境の使い分けやロールバックがとてもやりやすいのです。

また Next との親和性が非常に高く、Node サーバーとしての設定を 1 行も書かずに SSR 付きで Next アプリをデプロイすることができます。 また SSR のための正規表現を使ったルーティングもできます。

逆に言えば Node.js のサーバー側の知識をほぼ得ないままデプロイしてしまったので、勉強しなければと思ってはいます。

Markdown-it と katex について

実際に markdown のファイルをレンダリングする流れを説明します。 関連するディレクトリ構造は

- /pages
    - post.js
- /posts
    - hello-world.md

こんな感じです。posts フォルダの中に markdown 記事を入れていき、post.js でレンダリングします。

記事のページの実際の URL は /post?path=hello-world.md という形式で、 クエリ文字列から.md ファイルのパスを受け取って、動的に require しています。

const path = router.query.path    // hello-world.md
const { default: rawMarkdown } = require(`/posts/${path}`)

markdonw ファイルを直接 import/require するには raw-loader を使います。 Next では next.config.js に Webpack の設定を記述します。

Markdown-it と katex の連携はとても簡単で、markdown-it-katex をインストールして、

import markdonwIt from 'markdown-it'
import mk from 'markdown-it-katex'

const md = new markdownIt()
md.use(mk)

基本的にはこれだけです。あとは katex 用の css を読み込んでおくだけ。

B=0×E=BtD=ρ×H=J+Dt\begin{aligned} \nabla \cdot \bm{B} &= 0 \\ \nabla \times \bm{E} &= - \frac{\partial B}{\partial t} \\ \nabla \cdot \bm{D} &= \rho \\ \nabla \times \bm{H} &= J + \frac{\partial D}{\partial t} \end{aligned}

まとめ

Markdown を変換して記事にするブログなら、静的サイトジェネレータ(Hugoなど) を使うとかなり簡単にできるし、テーマも豊富です。 でも今回は Next.js の勉強も兼ねてやりたかったのです。その代わり時間がかかってしまいました。

また、Twitter のツイート埋め込みのような async で script を読み込んで表示するプラグインが動かないなど、 Markdown(静的)を SPA で扱うことによる弊害もあります。 このあたりの技術的検討をする上で得られた知見もまだまだありますが、それはまた別の記事で書きたいと思います。

またせっかく数式に対応したので、大学の勉強のまとめなんかも書いてみたいですね。書かない気はしますけど。

参考サイト

Next.js で自分用のブログを作った話

↑ この記事に触発されたのがブログを作ったきっかけです。nagano さんありがとうございます 🙏