Next.jsでブログを作った!

なぜブログを作ろうと思ったか

日々の思ったことを残すため

日々の生活で得る情報を、文章としてアウトプットするための場が欲しかったからです。インプットした情報を文章でアウトプットすると、頭の中が整理ができて、わかったこと・わからなかったことが明確になります。
日記や備忘が主な目的ですが、情報のアウトプットで少しでも誰かの役に立てたら嬉しいです。

React や Next.js の勉強のため

スキルアップのためにブログを自作しました。仕事では Web 業界で流行の技術に触れる機会が無く、強く危機感を抱きました 😱 アウトプットだけなら既存のサービスを利用しても良いのですが、スキルを身に着ける点で自分でブログを作りたいと思いました。

React と Next.js を選択した理由は次の 3 点です。

  • 流行しているから
  • 無料で使えるから
  • サクサク動くから

作ったもの(成果物)

当ブログです。

技術構成

Jamstack 構成です。DB、CSS フレームワーク、CMS などは使っていません。

React とは

Reactは、UI(ユーザーインターフェース)を構築するためのライブラリです。生みの親の Meta 社(旧 Facebook 社) はもちろん、多くの有名 IT 企業が React で開発をしています。JavaScript または TypeScript で記述できます。

今までの Web サイトは、画面を HTML と JavaScript を分けて記述して実装していたのですが、React は「HTML も JavaScript で書いたらいいのでは 🤔」と考えて生まれたそうです。

React は、機能ごとのパーツ=コンポーネントを作って組み合わせたり使いまわして画面を作るコンポーネント指向のライブラリです。コンポーネントを使って感じたメリットは次の 3 点です。

  • 影響範囲が狭い
  • 流用できる・拡張しやすい
  • デザインの統一がしやすい

大きなプロジェクトほど、このメリットを強く実感できると思います。

Next.js とは

Next.js は、React をベースとしたフロントエンドフレームワークです。

多くの機能を提供してくれる素晴らしいフレームワークです。React 単体では手間のかかる部分の実装を簡単にしてくれます。
代表的な機能は、

  • サーバーサイドでのページのレンダリング
  • ディレクトリでのルーティング
  • 最適化によるパフォーマンス向上

です。

サーバーサイドレンダリング(SSR)やスタティックサイト生成(SSG)によってページをサーバーサイドで事前にレンダリングすることで、初回のロード時間を短縮し、パフォーマンスを向上できます。サクサクです。

当ブログ作成前に、チュートリアルをやりました。このチュートリアルで作成したブログをもとに、機能の実装や CSS の追加などを施しながら当ブログを作成しました。

Learn | Next.js
Production grade React applications that scale. The world’s leading companies use Next.js by Vercel to build pre-rendered applications, static websites, and more.
nextjs.org
Learn | Next.js

TypeScript とは

TypeScript は、JavaScript の拡張版です。構文は JavaScript と基本的に同じですが、型をつけられるため正確かつ安全なコードを書くことができます。

JavaScript は、変数の型を定義する必要がないため、想定していない型のデータを入れてエラーが出たり、エラーが出てから原因を調べなければならなかったりと、何かと非効率でした 😢
TypeScript は、この問題を解決するために、型をつけられます。型を見ればどんな値が入るのかわかりますし、事前にエラーを表示してくれます。おかげでコードの品質が上がり保守性も高まります。

引数にnumber型、戻り値にstring型を定義した例です。:の後ろに型を記述します。引数がnumber型ではない場合、エラーが出ます。

const isOddOrEven = (x: number): string => {
  if (x % 2 === 0) {
    return `${x}は偶数です`
  } else {
    return `${x}は奇数です`
  }
}

console.log(isOddOrEven(1))
// OK! → "1は奇数です"

console.log(isOddOrEven('abc'))
// Error! → Argument of type 'string' is not assignable to parameter of type 'number'.

MDX とは

MDX は、Markdown の拡張版です。通常の Markdown と同じように文章を書ける上、JavaScript のコードや React コンポーネントを埋め込むこともできます。拡張子は.mdxです。

Markdown の中で、importを使ったりできます。当ブログでは、リンクカードなどの自作の React コンポーネント を MDX ファイル内で使用しています。下記は一例です。

import Button from 'button.js'

# 見出しです

本文です。

<Button>ボタンです</Button>

開発環境

  • Node.js をインストール済み
  • VSCode をインストール済み
  • 楽しむ心の余裕を持つ

機能の実装

開設時までに実装した機能は下記です。

  • MDX 形式での記事の作成
  • カテゴリーやタグでの記事分類
  • カテゴリーおよびタグ別記事一覧
  • ページネーション
  • 記事の検索

MDX 形式での記事の作成

Next.js のチュートリアルでは Markdown を使用していますが、React コンポーネントを使いたいから MDX を採用しました。

MDX のを使うために next-mdx-remote を使用しています。記事の MDX ファイルは下記のように記述しています。Frontmatter には、記事タイトル、日付、タグ、サムネイル画像 URL を記述しています。本文は Markdown 形式で書いています。

---
title: 記事タイトル
date: '2024-01-01'
tags: [タグ1, タグ2, タグ3]
thumbnail: test.jpg
---

## 見出しだよ

記事本文だよ。

カテゴリーの記事分類

ブログサービスによくある、記事をカテゴリーで分けられる機能です。
カテゴリーごとにディレクトリを作成して記事を管理しています。

先人の知恵をお借りしたかったのですが、Next.js で実装している例がなかなか見つからず…。当ブログでの実装例を一部ですが紹介します。

ディレクトリ構成

記事のファイルを管理するためのディレクトリ _posts をプロジェクトの直下に作成します。
次に、_posts 下にカテゴリーのディレクトリを作ります。そして、その下に記事のファイルを作成します。
次のようなディレクトリ構成で記事を管理しています。

_posts
  ├── category1
  │   ├── post1.mdx
  │   ├── post2.mdx
  │   └── post3.mdx
  ├── category2
  │   ├── post1.mdx
  │   ├── post2.mdx
  │   └── post3.mdx
  └── category3
      ├── post1.mdx
      ├── post2.mdx
      └── post3.mdx

記事ページのディレクトリ構成は次のようになっています。_posts 下のディレクトリ名とファイル名は各記事にアクセスする際の URL の一部になります。例:https://example.com/post/category1/post1

app
  └──post
      └── [category]
            └── [slug]
                  └── page.tsx

page.tsx 内のgenerateStaticParams()で、カテゴリーと記事ファイル名を使ってルーティングを設定します。カテゴリーのディレクトリ名とファイル名を配列で渡します。

export async function generateStaticParams() {
  const params = await getAllPostParams()
  // [{ category: 'category1', slug: 'post1' },{ category: 'category1', slug: 'post2' },{ category: 'category1', slug: 'post3' },{ category: 'category2', slug: 'post1' },...]
  return params.map((param) => ({ category: param.category, slug: param.slug }))
}

カテゴリー名の管理

カテゴリーは、ディレクトリ名と表示名を yaml ファイルで管理しています。プロジェクト直下に meta ディレクトリを作成し、その下に categories.yaml を作成します。

yaml ファイルは次のように記述します。slugはディレクトリ名、nameはサイトでの表示名です。

categories:
  - slug: category1
    name: カテゴリー1
  - slug: category2
    name: カテゴリー2
  - slug: category3
    name: カテゴリー3

yaml ファイルを扱うために、yaml-loader をインストールします。

npm install yaml-loader

next.config.js ファイルに追記して使えるようにします。

module.exports = {
  webpack: function (config) {
    config.module.rules.push({
      test: /\.ya?ml$/,
      oneOf: [
        {
          resourceQuery: /stream/,
          options: { asStream: true },
          loader: 'yaml-loader',
        },
        { loader: 'yaml-loader' },
      ],
    })
    return config
  },
}

categories.ts を作成して、カテゴリーを取得する処理を作ります。記事の取得やルーティングのために使用します。なお、yaml ファイルに記載していないディレクトリは取得しません。

import categories from '@meta/categories.yaml'

type CategoryContent = {
  slug: string
  name: string
}

function generateCategoryMap(): { [key: string]: CategoryContent } {
  const result: { [key: string]: CategoryContent } = {}
  for (const category of categories.categories) {
    result[category.slug] = category
  }
  return result
}

カテゴリーおよびタグ別記事一覧

一覧ページです。カテゴリーに一致する記事、タグを含む記事を取得して一覧で表示します。

ページネーションは下記を参考にしました。

[Next.js]App Router時代の静的サイトの作り方
zenn.dev
[Next.js]App Router時代の静的サイトの作り方

App Router でのルーティングと画面の表示

当初は Page Router で作っていましたが、App Router で作り直しました。App Router のほうがわかりやすくコンポーネントやデータフェッチを扱える印象です。

App Router ではコンポーネントでデータフェッチ できるのが便利!  Page Router では、GetStaticPropsで取得したデータをコンポーネントに渡してリレーしていましたのですが、App Router でそのあたりの無駄な処理を減らせました。

デザイン

お菓子のカスタードプリンが好きなので、Web サイトのデザインにしました 🍮🍮🍮🍮🍮

CSS フレームワークは使っていません。CSS は勉強のためにチマチマと書きました。SVG ファイルも作成したりフリー素材から拝借しました。楽しいです。

好き勝手に作っているので、良いデザインを学ばないといけないと痛感しています。

参考書籍・サイト

公式ドキュメントやさまざまなサイトを参考にしました。偉大な先人たちに感謝です。

ES2015(ES6)以降の JavaScript の基本の勉強になった書籍です。ES2015 にいまいち自信が無かったため、基本から学び直しました。

モダンJavaScriptの基本から始める React実践の教科書
www.amazon.co.jp
モダンJavaScriptの基本から始める React実践の教科書

Next.js の App Router の参考になりました。

[Next.js]App Router時代の静的サイトの作り方
zenn.dev
[Next.js]App Router時代の静的サイトの作り方

おわりに

React を使ってみて、開発スピードの向上を感じました。コンポーネントを使いまわせるだけでもすごい便利です。Next.js も、設定などが複雑ではなく、SSG などを実現する機能もシンプルでわかりやすいため、開発しやすいと思いました。大きな労力を必要とせずにサクサク動く Web サイトを作成できて、楽しいです。

まだまだわかっていない部分ばかりですし、どんどんアップデートされていっていますので、勉強の余地しかないです。当ブログにも機能を追加していきたいです。

Share