Open9

Next.js + microCMSでポートフォリオっぽいものを作る

ym5754nym5754n

想定環境

  • Next.js: 最近フロントエンドの勉強として触り始めて楽しいので
  • microCMS: 都度更新するコンテンツについてはここで追加していく
  • vercel or github pages: デプロイ先は検討中。ポートフォリオを目指して作るならgithubでまとめて管理したい気持ちはある

載せたいコンテンツ

  • 自己紹介
  • 学習記録(自らへの戒めを込めて)
  • 映画、本の記録(ただAPIとかの勉強がてら載せたいのと、趣味なので)
  • その他思いついたら都度追加

技術的に達成したいこと

  • Next.jsでイチからなにか作れるようになる
  • 自動テストをかけるようになる
  • CI/CDについて理解する
ym5754nym5754n

vercelかgithub pagesかという点で、今回はgithub pagesを採用したい

  • Next.jsのApp Routerを存分に使ってみたい
  • github pagesは静的サイトしか扱えないので↑の制約はあるが、目的としてるサイトではそこまで影響なさそう
  • github actionsを使ってみたい

参考

NEXT.JS - Static Exports

Unsupported Features
Features that require a Node.js server, or dynamic logic that cannot be computed during the build process, are not supported:
Dynamic Routes with dynamicParams: true
Dynamic Routes without generateStaticParams()
Route Handlers that rely on Request
Cookies
Rewrites
Redirects
Headers
Middleware
Incremental Static Regeneration
Image Optimization with the default loader
Draft Mode

GitHub Docs - GitHub Pages について

GitHub Pages は、リポジトリにプッシュされたあらゆる静的ファイルを公開します。

ym5754nym5754n

Next.js 14をgithub pagesで公開する

プロジェクトの作成 && SSG用設定

とりあえずお決まりのコマンドでnext.jsのプロジェクトを作る

npx create-next-app@latest .

SSG用にconfigファイルを書き換える

next.config.mjs
/** @type {import('next').NextConfig} */
const nextConfig = {
    output:'export',
};
/* module.exports = nextConfig*/
export default nextConfig;

githubでgithub pages用のリポジトリを作る

  • リポジトリ名は「[ユーザ名].github.io」で作る
  • プロジェクトをリポジトリにプッシュ

github pagesの設定を行う

こちらを参照
https://tech-lab.sios.jp/archives/33691#GitHub_Pageyml

ymlファイルの書き換え

こちらを参考にymlファイルの以下をすべてコメントアウト
https://github.com/vercel/next.js/discussions/58790

nextjs.yml
- name: Setup Pages
  uses: actions/configure-pages@v4
    with:
      # Automatically inject basePath in your Next.js configuration file and disable
      # server side image optimization (https://nextjs.org/docs/api-reference/next/image#unoptimized).
      #
      # You may remove this line if you want to manage the configuration yourself.
      static_site_generator: next
nextjs.yml
- name: Static HTML export with Next.js
  run: ${{ steps.detect-package-manager.outputs.runner }} next export

変更をCommitしたら自動でデプロイが始まるので完了まで待つ

確認

リポジトリのSetting>Pages>Visit SiteでNextjsのTOPページが表示されたらOK

余談

14で同じようなことをしている日本語記事が無かったのと、Actionsを初めて触ってので少し手こずった。
discussionありがたい🙏

ym5754nym5754n

microCMSの環境変数にgithub actionsからアクセスできるようにする

github actionsでnextjsデプロイ時に環境変数が取得できずビルドエラーが発生
以下の対応を実施

1. githubに環境変数を追加

settingから環境変数を追加
settings > environments > github-pages > Add secretで必要な環境変数を追加

2. github actionsで.envファイルを作成

ymlファイルに以下の記述を追加

.github/workflows/nextjs.yml
build:
    runs-on: ubuntu-latest
    environment: # ←これ
      name: github-pages # ←これ
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      - name: Create .env file # ←これ
        run: | # ←これ
          echo "MICROCMS_API_KEY=${{ secrets.MICROCMS_API_KEY }}" >> .env # ←これ
          echo "MICROCMS_SERVICE_DOMAIN=${{ secrets.MICROCMS_SERVICE_DOMAIN }}" >> .env # ←これ
ym5754nym5754n

トレイリングスラッシュについて

SSGの場合、デフォルトだとトレイリングスラッシュありのURLにアクセスすると404になる
以下を追加してトレイリングスラッシュありの場合でもページにアクセスできるようにする

next.config.mjs
const nextConfig = {
    output:'export',
    trailingSlash: true, // 追加
};

https://nextjs.org/docs/app/api-reference/next-config-js/trailingSlash

ym5754nym5754n

ブログ記事のパーマリンクについて

https://github.com/vercel/next.js/discussions/58549
まさにこの問題(未解決)

現状

microCMSから記事詳細を取得する際には記事ごとに発行されるユニークidをキーにリクエストする必要がある。そのため、 記事詳細のリンクを/[id]とし、generateStaticParamsでそのidでページを生成し、paramsのidを取得して記事内容を取得している

page.tsx
export async function generateStaticParams() {
  const posts = await client.get({ endpoint: "blog" });
 
  return posts.contents.map((post: Blog) => ({
    id: post.id,
  }))
}

export default async function Post({ params }: { params: { id: string } }) {
  const post: Blog = await getData(params.id);
...(記事内容の出力処理)

やりたいこと

SEO的にランダムな文字列をパーマリンクとすることは微妙なので、できれば自分が指定したパーマリンクを生成し、idは裏側で受け渡して記事内容を取得できるようにしたい

問題

SSGにおいてgenerateStaticParamsはルーティングのためのparamsを生成することしかできないので、独自のパーマリンクを追加のparamsとして加えることができない
↓こんな感じのことをしたい

page.tsx
export async function generateStaticParams() {
  const posts = await client.get({ endpoint: "blog" });
 
  return posts.contents.map((post: Blog) => ({
    parmalink: post.parmalink, // /[parmalink]としてURLを生成
    id: post.id, // idをparamsとして渡して記事詳細を取得
  }))
}

export default async function Post({ params }: { params: { id: string } }) {
  const post: Blog = await getData(params.id);

対応

今のところ解決策が見つからないのと、個人ブログでアクセス数をあまり気にしていないので一旦対応を見送る

ym5754nym5754n

最上位のタグが不要でkeyを指定したい場合

パンくずリストの一部をmapを使って出力していたが、keyを指定していないためにWarningが発生

breadcrumb.tsx
{segments.map((segment, key) => {
    joinedSegment += segment + "/";
    display = key === 0 ? segment.charAt(0).toUpperCase() + segment.slice(1) : segment;
    return (
        <>
            <BreadcrumbSeparator />
            <BreadcrumbItem key={key}>
              {key < segments.length - 1
                ? <BreadcrumbLink href={`/${joinedSegment}`}>{display}</BreadcrumbLink>
                : <BreadcrumbPage>{display}</BreadcrumbPage>
              }
            </BreadcrumbItem>
        </>
    );
})}

Fragmentの省略記法(<>)ではkeyを指定できないので、明示的に<Fragment>としてkeyを追加する

breadcrumb.tsx
{segments.map((segment, key) => {
    joinedSegment += segment + "/";
    display = key === 0 ? segment.charAt(0).toUpperCase() + segment.slice(1) : segment;
    return (
        <Fragment key={key}> {/* ここ */}
            <BreadcrumbSeparator />
            <BreadcrumbItem key={key}>
              {key < segments.length - 1
                ? <BreadcrumbLink href={`/${joinedSegment}`}>{display}</BreadcrumbLink>
                : <BreadcrumbPage>{display}</BreadcrumbPage>
              }
            </BreadcrumbItem>
        </Fragment> {/* ここ */}
    );
})}

https://ja.react.dev/reference/react/Fragment

ym5754nym5754n

microCMSの記事一覧が更新されない

github actionsでデプロイが完了してもmicroCMSで追加した記事が更新されない
nextjsのcacheが効いているせいで過去のデータを持ってきているよう
github actionsでbuildコマンドを流す前にcacheファイルを削除する

nextjs.yml
      - name: Install dependencies
        run: ${{ steps.detect-package-manager.outputs.manager }} ${{ steps.detect-package-manager.outputs.command }}
      - name: Remove cache files # 追加
        run: rm -rf .next/cache/fetch-cache # 追加
      - name: Build with Next.js
        run: ${{ steps.detect-package-manager.outputs.runner }} next build

https://help.microcms.io/ja/knowledge/app-router-cache