r.blog

Next.js × docker-compose × microCMS × VercelでJAMstackブログを作る - 01

Next.jsとDockerの勉強に、docker-compose、microCMS、Vercelを使用してシンプルなブログを作ってみました。このサイトです。
Next.js、React、Dockerも触りたてでしたが、サクッと作れたので備忘録も兼ねて紹介します。
※初心者ゆえ認識違いなことがたくさんあるかもしれません、ご了承ください。。

使用技術

  • node.js
  • Next.js(React)
  • Docker(docker-compose)
  • GitHub
  • microCMS
  • Vercel


今回作るにあたりメインで参考にさせていただいたmicroCMSチュートリアルはこちら!
microCMS + Next.jsでJamstackブログを作ってみよう | microCMSブログ

JAMstackブログを作る

node.js、Dockerインストール済、GitHubアカウント接続済の前提で進めます。
your-project-name your-app-nameという名前は適宜変えて読んでください。

1. Docker(Docker-Compose)の設定

チュートリアルではホストマシンにNext.jsプロジェクトなどあれやこれやをインストールしていますが、今回はDocker(docker-compose)でnode.jsイメージベースのコンテナを作成し、その中にプロジェクトをインストール、環境構築をしていきます。

ディレクトリの作成

Next.jsプロジェクトを置くディレクトリを作成します。
私はhome直下に開発用ディレクトリ(develop)を作成していたので、その中にプロジェクトディレクトリを作成しました。
/Users/ユーザー名/develop/your-project-name

Dockerfileを作成

Dockerfileとは、Dockerイメージを作成するための設定書のようなものです。
先程作ったyour-project-nameディレクトリ直下に作成します。#以下コメントは削除してください。

/Dockerfile
FROM node:14.17.4-alpine #使用するイメージ
WORKDIR /usr/src/app/next #サーバーのワークディレクトリを設定する
RUN npm install #npmインストール


docker-compose.yml作成

docker-compose.ymlとは、Dockerコンテナを作成するための設定書のようなものです。
こちらもyour-project-nameディレクトリ直下に作成します。

/docker-compose.yml
version: "3" #このdocker-compose.ymlのバージョン
services: #起動するサービス(コンテナ)の設定定義
  your-app-name: #「your-app-name」という名前でサービスを定義
    build: . #パスにあるDockerfileを実行
    ports: #ポート設定
      - "3000:3000" #左辺がローカル、右辺がコンテナのポート localostの3000番ポートあてにアクセスすると、コンテナの3000番ポートあてに転送
    container_name: your-app-name #コンテナ名の設定
    volumes: #データのマウント設定
      - .:/usr/src/app/next #データのマウント設定 左辺がローカル、右辺がコンテナのマウント先
    command: sh -c "cd your-app-name && npm run dev" #起動後にコマンド実行


Next.jsプロジェクトのインストール

ターミナルを開き、$ cdでyour-project-nameディレクトリ直下に移動、コンテナを起動、その中でNext.jsプロジェクトを作成します。

$ cd /Users/ユーザー名/develop/your-project-name #your-project-nameディレクトリに移動
$ docker-compose run --rm your-app-name npx create-next-app your-app-name --use-npm

docker-compose runはコンテナを1回だけ作成・起動します。
—rmオプションは起動後にコンテナを削除します。
次のyour-app-nameはdocker-compose.ymlのservicesを指します。
npx create-next-app your-app-nameはチュートリアルにもあるように、next.jsプロジェクトを作成します。
--use-npmオプションは使用するパッケージマネージャをnpmに指定します。

インストールが終わると、your-project-nameディレクトリ直下にnext.jsプロジェクトのyour-app-nameディレクトリができます👏

コンテナの作成

続けてコンテナを作成、起動します。イメージは先程の$ docker-compose runで作られているので省略。

$ docker-compose up -d  #コンテナの作成と起動

-dオプションはターミナルを占有せず、バックグラウンドで起動します。
占有しないとはどういうこと?と思う方は-dをつけずに実行するとわかるかと思います。Ctrl+Cで抜けられます。

localhost:3000にアクセスして、スタートページが表示されたら成功です🎉
コンテナの中で開発サーバーが起動し、your-app-nameディレクトリの中身を表示できています。
コンテナの起動・停止はコマンドからもできますが、私はDocker Desktopアプリケーションから行っています。

2. GitHubにリポジトリ作成

この時点で一度Githubにリポジトリを作成し上げておきます。

リポジトリを新規作成

Create a new repositoryからリポジトリを新規作成します。

.gitignoreの設定

your-app-nameディレクトリ直下にある.gitignoreをyour-project-nameディレクトリ直下に移動させ、データ内のスラッシュから始まっているもののスラッシュを削除し、各種ディレクトリ、フォルダをgitから除外します。

/.gitignore
#例
/node_modules → node_modules

ドットから始まるファイルはデフォルトではfinderで表示されないため、[command] + [shift] + [.(ドット)]を押して表示させてください。ターミナルで表示設定する方法もあります。

gitの設定

リポジトリとプロジェクトを結びつけます。

$ git init #gitリポジトリを新規作成
$ git branch -m main #デフォルトブランチをmainに変える
$ git add --all #すべての変更をインデックスに追加する
$ git commit -m 'first commit' #コミットメッセージをつけてコミットする
$ git remote add origin git@github.com:ユーザー名/リポジトリ名.git #リポジトリとの紐付け SSHかHTTPSで記述が変わってくるので環境に合わせてください
$ git push -u origin main #コミットをプッシュ

GitHubでfirst commitができていればOKです🎉

以降は、キリのいいところで都度コミット&プッシュしておくと良いと思います🙆‍♀️

$ git add --all #すべての変更をインデックスに追加する
$ git commit -m 'first commit' #コミットメッセージをつけてコミットする
$ git push origin main #コミットをプッシュ


4. microCMSの用意をする

Finderとターミナルからは一旦離れ、ブログコンテンツとなるAPIをmicroCMSで作成します。
アカウント作成、サービスの作成、APIの作成は公式チュートリアルにあるので割愛します。
APIスキーマについては、自分は任意に投稿日時を変えたかったので
【フィールドID:date、表示名:日付 種類:日時】を追加しました。
APIスキーマなどはAPIページの右上API設定>APIスキーマから変更、追加できます。

APIスキーマが作成できたら、右上の追加ボタンからコンテンツを新規作成し、適当に内容を入力して公開。
コンテンツ一覧画面に戻り、右上のAPIプレビューをクリック、取得ボタンをクリックし、レスポンスが200、レスポンスJSONが表示されたらOKです。

左上にあるX-MICROCMS-API-KEY :をコピーしておきます。

5. APIキーを設定する

APIキーとはサービスに紐付けられた文字列のことで、Next.jsプロジェクトからmicroCMSにAPI取得のリクエストを送る際にこれを一緒に送ることで特定のコンテンツのAPIを呼び出します。サービス利用するためのパスワードみたいなものでいいかと思います。

こういった、gitに上げるべきではないパスワード、また環境ごとに異なる設定(例:DBへの接続設定)などは、.envファイルで管理します。
.envファイルは.gitignoreで除外されているのでgitに上がってきません。

your-app-nameディレクトリ直下に.env.development.localを作成します。

/your-app-name/.env.development.local
API_KEY=xxxxxxxxxxxx #先程コピーしたX-MICROCMS-API-KEY
SERVICE_DOMAIN=xxxxxxxx #microCMSのサービスID XXXX.microcms.ioのXXXXの部分


6. microcms-js-sdkのインストール

microCMSをNext.jsで扱えるようにするために、microcms-js-sdkをインストールします。
コンテナの中に入り、その中でインストールをしていきます。
Dockerfileに記述するやり方もあると思いますが、個人的にこっちの方がコンテナの理解に繋がったのでこの方法で進めていきます。

your-project-name
$ docker-compose stop #コンテナ起動していたらこのコマンドでコンテナ停止 
$ docker-compose run --rm your-app-name /bin/sh #コンテナを一時的に起動し中に入る 
=====ここからコンテナ内=====
# ls #ディレクトリ内を確認 docker-compose.yml、Dockerfile、your-app-nameがあると思います
# cd your-app-name #your-app-nameディレクトリに入る
# npm install microcms-js-sdk #microcms-js-sdkをインストール
# exit #コンテナを抜ける 
=====ここまでコンテナ内=====

コンテナの中のyour-app-nameディレクトリにインストールしましたが、コンテナとホスト側ディレクトリはマウントしているので、ホスト側にも反映されます。
your-app-nameディレクトリ内のpackage.jsondependenciesmicrocms-js-sdkが追加されていればOKです🎉

your-app-nameディレクトリ直下にlibsディレクトリとその中にclient.jsを作成します。

/your-app-name/libs/client.js
import { createClient } from 'microcms-js-sdk';

export const client = createClient({
  serviceDomain: process.env.SERVICE_DOMAIN,
  apiKey: process.env.API_KEY,
});

process.env.*は先程作成した.envファイルを参照しています。

7. ブログの一覧ページを表示する

microCMSをNext.jsで扱えるようになったので、いよいよデータを取得し、ページに表示していきます。
pages/index.jsを変更します。中身まるっとこれに置き換えでOK。

/your-app-name/pages/index.js
import Link from "next/link";
import { client } from "../libs/client";

export default function Home({ blog }) {
  return (
    <div>
      <ul>
        {blog.map((blog) => (
          <li key={blog.id}>
            <Link href={`/blog/${blog.id}`}>
              <a>{blog.title}</a>
            </Link>
          </li>
        ))}
      </ul>
    </div>
  );
}

// データをテンプレートに受け渡す部分の処理を記述します
export const getStaticProps = async () => {
  const data = await client.get({ endpoint: "blog" });

  return {
    props: {
      blog: data.contents,
    },
  };
};

コンテナを起動し、localhost:3000にアクセスして、タイトルが取得できていたら成功です🎉

8. ブログの詳細ページを表示する

続けてブログの詳細ページを作っていきます。
pagesディレクトリ内にblogディレクトリを作成し、その中に[id].jsを作成します。

/your-app-name/pages/blog/[id].js
import { client } from "../../libs/client";

export default function BlogId({ blog }) {
  return (
    <main>
      <h1>{blog.title}</h1>
      <p>{blog.date}</p>
      <div
        dangerouslySetInnerHTML={{
          __html: `${blog.body}`,
        }}
      />
    </main>
  );
}

// 静的生成のためのパスを指定します
export const getStaticPaths = async () => {
  const data = await client.get({ endpoint: "blog" });

  const paths = data.contents.map((content) => `/blog/${content.id}`);
  return { paths, fallback: false };
};

// データをテンプレートに受け渡す部分の処理を記述します
export const getStaticProps = async (context) => {
  const id = context.params.id;
  const data = await client.get({ endpoint: "blog", contentId: id });

  return {
    props: {
      blog: data,
    },
  };
};

localhost:3000にアクセス、記事タイトルをクリックし詳細ページが見れたら成功です🎉🎉



次回は日付のフォーマット、レイアウトの調整、css(sass)で装飾、Googlefontの読み込み、ホスティングと公開を紹介します。


参考サイト

Docker周り
Dockerで、Next.js,TypeScript環境構築方法
Docker ComposeでNext.js開発環境構築
docker-compose を使った Node.js・npm 開発環境構築例
DockerでNode.jsアプリケーションを開発する (1) Express.jsをコンテナ内で動かす