【メモ】Next.js初心者として疑問点の整理

Difyでの活用を目的にSpabaseとNext.jsをまず触ってみようと思い、その中でNext.jsについて確認したことをメモ。


まず、基本的な大抵の知識はこちらのサイトでわかりやすく書いてくれています。それを読みながらNext.js初心者目線で自分が疑問に思ったこと、またそれを羅列しただけだと散らかりそうなので、唐突すぎない程度に前後の説明(リンク先にも書いてあること)を加えて書いています。

1. ファイル構成

1.1 基本的なフォルダ構成

※Perprexity @Cloud 3.5 Sonnet wrote

project-root/
 ├── app/
 │  ├── layout.tsx
 │  ├── page.tsx
 │  ├── loading.tsx
 │  ├── error.tsx
 │  └── [...nested-routes]/
 │    ├── page.tsx
 │    └── layout.tsx
 ├── components/
 │    ├── elements/
 │    │  ├── Button.tsx
 │    │  └── Input.tsx
 │    └── layouts/
 │      ├── Header.tsx
 │      └── Footer.tsx
 ├── public/
 │  ├── images/
 │  └── fonts/
 ├── styles/
 │  └── globals.css
 ├── features/
 │  └── auth/
 │  ├── components/
 │  └── hooks/
 ├── hooks/
 │  └── useCustomHook.ts
 ├── types/
 │  └── index.ts
 ├── utils/
 │  └── helpers.ts
 ├── next.config.js
 ├── package.json
 ├── tsconfig.json
 └── .env

プロジェクトのルート

Next.jsプロジェクトのルートには、以下の重要なファイルが配置されます:

  • `next.config.js`: Next.jsの設定ファイルで、カスタム設定や環境変数の定義を行います。

  • `package.json`: プロジェクトの依存関係や実行スクリプトを管理します。

  • `.env`: 環境変数を管理するファイルです。

  • `middleware.ts`: リクエストの前処理や後処理を実行するためのカスタムコードを記述します。

主要なディレクトリ

app/

App Routerを使用する場合のメインフォルダです。このディレクトリ内のファイル構造がアプリケーションのルーティングに直接対応します。

主要なファイル:

  • `layout.js/.jsx/.tsx`: 複数のページで共通のレイアウトを定義します。

  • `page.js/.jsx/.tsx`: 各ページのコンテンツを定義します。

  • `loading.js/.jsx/.tsx`: データ読み込み中のUI表示を定義します。

  • `error.js/.jsx/.tsx`: エラー発生時のUI表示を定義します。

components/

アプリケーション全体で共通して使用されるコンポーネントを格納します。一般的に以下のようなサブディレクトリを含みます:

  • `elements/`: ボタンなどの基本的なUIコンポーネント

  • `layouts/`: ヘッダーやフッターなどのレイアウトコンポーネント

public/

静的ファイル(画像、フォントなど)を格納するディレクトリです。

styles/

スタイリングに関するファイルを格納します。

その他のディレクトリ

  • `features/`: 特定の機能やドメイン専用のコンポーネントやロジックを格納します。

  • `hooks/`: カスタムフックを格納します。

  • `types/`: TypeScriptの型定義ファイルを格納します。

  • `utils/`: ユーティリティ関数を格納します。

1.2 アクセス時の参照順序

基本的な参照順序

  1. ルートディレクトリ
    まず、プロジェクトのルートディレクトリが参照されます。

  2. app/ ディレクトリ
    Next.js 13以降のApp Routerを使用している場合、`app/`ディレクトリが最初に参照されます。

  3. pages/ ディレクトリ
    従来のPages Routerを使用している場合や、App Routerと併用している場合は`pages/`ディレクトリも参照されます。

ファイル参照の優先順位

  1. index.js / index.tsx
    ディレクトリ内で最初に参照されるのは`index.js`または`index.tsx`ファイルです。

  2. page.js / page.tsx
    App Routerを使用している場合、`page.js`または`page.tsx`ファイルが参照されます。

  3. 動的ルーティング
    `[param].js`や`[...param].js`のような動的ルーティングファイルが存在する場合、URLに応じてこれらが参照されます。

レイアウトとコンポーネントの適用

  1. layout.js / layout.tsx
    App Routerでは、レイアウトファイルが存在する場合、これが適用されます。

  2. コンポーネントの読み込み
    `page.js`や`index.js`内で定義されたコンポーネントが読み込まれ、レンダリングされます。

特殊なファイル

  • _app.js / _app.tsx: Pages Routerでグローバルレイアウトを定義する場合に使用します。

  • _document.js / _document.tsx: HTMLドキュメント全体の構造をカスタマイズする場合に使用します。

注意点

  • App RouterとPages Routerを併用している場合、App Routerが優先されます。

  • `public/`ディレクトリは静的ファイルの配信に使用され、ルーティングには直接関与しません。

1.3 依存関係

ルーティングの基本構造

Next.jsのルーティングは、`app/`ディレクトリ(App Router使用時)または`pages/`ディレクトリ(Pages Router使用時)の構造に直接対応します。

ファイルの依存関係

layout.tsx

  • 複数のページで共有されるレイアウトを定義します。

  • 子ページやコンポーネントをラップします。

  • 親ディレクトリのlayoutは、子ディレクトリのlayoutを包含します[1]。

page.tsx

  • 特定のルートのメインコンテンツを定義します。

  • 対応するlayoutがある場合、そのlayout内にレンダリングされます。

loading.tsx

  • ページやコンポーネントの読み込み中に表示されるUIを定義します。

  • 対応するpage.tsxと同じディレクトリに配置します。

error.tsx

  • エラー発生時に表示されるUIを定義します。

  • 対応するpage.tsxと同じディレクトリに配置します。

フォルダの依存関係

  • ルートディレクトリ: プロジェクト全体の設定や共通ファイルを含みます。

  • `app/`: App Routerを使用する場合のメインディレクトリです。

  • `components/`: 再利用可能なコンポーネントを格納します。

  • `public/`: 静的ファイルを格納し、直接アクセス可能です。

特殊なファイルとフォルダ

  • `[folder]`: 動的ルーティングを表します。URLパラメータとして使用されます[4]。

  • `(folder)`: グループ化のためのフォルダで、URLには影響しません。

依存関係の例

  1. `app/layout.tsx`はアプリケーション全体のレイアウトを定義します。

  2. `app/page.tsx`はルートページのコンテンツを定義します。

  3. `app/about/page.tsx`は`/about`ルートのコンテンツを定義します。

  4. `app/about/layout.tsx`は`/about`とその子ページ専用のレイアウトを定義します。

この構造により、ファイルシステムベースのルーティングが実現され、ディレクトリ構造がそのままURLパスに反映されます。また、レイアウトの入れ子構造により、コードの再利用性と保守性が向上します。

1.4 重要なポイント

  • app/ディレクトリ内のフォルダ構造がそのままURLパスになります。

  • layout.tsxは親レイアウトを定義し、子ルートに継承されます。

  • page.tsxはそのルートの実際のコンテンツを定義します。

  • コンポーネントの分割と再利用を意識し、components/ディレクトリを活用しましょう。

  • 共通のロジックはlib/ディレクトリにまとめることで、コードの重複を避けられます。

2. QA @Claude 3.5 Sonnet

2.1 静的サイトジェネレーションとサーバーレンダリングの違いは?

Next.jsの静的サイトジェネレーション(SSG)とサーバーサイドレンダリング(SSR)には、以下のような主な違いがあります:

静的サイトジェネレーション(SSG)

  1. レンダリングタイミング:

    • ビルド時にHTMLを生成します。

  2. パフォーマンス:

    • 事前に生成されたHTMLを提供するため、非常に高速です。

  3. 適用シーン:

    • コンテンツが頻繁に変更されないサイト(ブログ、ドキュメントサイトなど)に適しています。

  4. スケーラビリティ:

    • 静的ファイルはCDNで効率的に配信できるため、スケーラビリティが高いです。

  5. データ更新:

    • ビルド後にデータを変更することは難しいです。

サーバーサイドレンダリング(SSR)

  1. レンダリングタイミング:

    • リクエストごとにサーバー上でHTMLを生成します。

  2. パフォーマンス:

    • SSGよりは遅いですが、動的コンテンツを提供できます。

  3. 適用シーン:

    • ユーザーごとに異なるコンテンツや、頻繁に更新されるデータを扱うページに適しています。

  4. 最新性:

    • 常に最新のデータでページを生成できます。

  5. サーバーリソース:

    • リクエストごとにサーバーリソースを使用するため、SSGよりも負荷が高くなる可能性があります。

選択基準

  • 「ユーザーのリクエストより先にこのページをPre-renderingすることができますか?」という質問にYESと答えられる場合はSSGを選択します。

  • 頻繁なデータ更新や、ユーザーごとに異なるコンテンツを提供する必要がある場合はSSRを選択します。

Next.jsでは、これらのレンダリング方法を柔軟に組み合わせることができ、ページごとに最適な方法を選択できます。これにより、パフォーマンスとユーザー体験を最適化したWebアプリケーションを構築することが可能です。

2.2 ファイルベースのルーティングとは何ですか?

ファイルベースのルーティングとは、Webアプリケーションのルーティング(URLとページの対応付け)をファイルシステムの構造に基づいて自動的に生成する方法です。主な特徴は以下の通りです:

  1. ディレクトリ構造がURLパスに対応:
    特定のディレクトリ(例:Next.jsの`pages`や`app`)配下のファイル構造がそのままURLパスになります。

  2. ファイル名がルートを定義:
    ファイル名がURLの一部になります。例えば`pages/about.js`は`/about`というURLに対応します。

  3. 動的ルーティングのサポート:
    ファイル名に特殊な記法(例:[id].js)を使うことで、動的なURLパラメータを扱えます。

  4. ネストされたルーティング:
    フォルダ構造を使ってネストされたルートを簡単に作成できます。

  5. 設定ファイル不要:
    別途ルーティング設定ファイルを書く必要がなく、ファイルを配置するだけでルートが生成されます。

  6. コード分割の容易さ:
    ファイルごとに自動的にコード分割されるため、パフォーマンス最適化が容易です。

  7. 直感的な構造:
    プロジェクト構造を見るだけでアプリケーションのルート構造が理解しやすくなります。

ファイルベースのルーティングは、Next.js、Nuxt.js、SvelteKitなどの現代的なフレームワークで採用されており、開発者の生産性向上とコードの整理に役立っています。

2.3 appとpagesディレクトリの違いは何ですか?

appディレクトリとpagesディレクトリの主な違いは以下の通りです:

  1. ルーティング方式:

    • appディレクトリはApp Routerを使用し、ファイルシステムベースのルーティングを採用しています。

    • pagesディレクトリはPages Routerを使用し、従来のNext.jsのルーティング方式を採用しています。

  2. デフォルトのレンダリング:

    • appディレクトリではデフォルトでサーバーサイドレンダリング(SSR)が適用されます。

    • pagesディレクトリではデフォルトでクライアントサイドレンダリングが適用されます。

  3. データフェッチング:

    • appディレクトリでは、標準のfetch APIとasync/await構文を使用してデータをフェッチします。

    • pagesディレクトリでは、getServerSidePropsやgetStaticPropsなどの特別なデータフェッチング関数を使用します。

  4. コンポーネントの種類:

    • appディレクトリではReact Server Components (RSC)がデフォルトで使用されます。

    • pagesディレクトリではクライアントコンポーネントがデフォルトです。

  5. ファイル構造:

    • appディレクトリでは、layout.tsx、page.tsx、loading.tsxなど、特定の命名規則に基づいたファイルを使用します。

    • pagesディレクトリでは、各ファイルが直接ルートに対応します。

  6. 将来性:

    • appディレクトリは新しい機能であり、今後のNext.jsの開発の中心となることが期待されています。

    • pagesディレクトリは従来の方式であり、将来的には廃止される可能性があります。

appディレクトリは、より柔軟なルーティング、改善されたパフォーマンス、そしてReact 18の新機能を活用できるため、新しいプロジェクトでは推奨されています。一方、pagesディレクトリは既存のプロジェクトとの互換性を維持するために引き続きサポートされています。

2.4 appディレクトリのlayoutファイルの役割は何ですか?

appディレクトリのlayoutファイルは、Next.jsアプリケーションにおいて重要な役割を果たします。主な役割は以下の通りです:

  1. 共通UIの定義:
    複数のページで共有されるUIコンポーネント(ヘッダー、フッター、ナビゲーションなど)を定義します。

  2. ルートレイアウトの設定:
    appディレクトリのルートにある`layout.js`ファイルは、アプリケーション全体に適用されるルートレイアウトを定義します。

  3. HTML構造の定義:
    ルートレイアウトでは、`<html>`と`<body>`タグを定義する必要があります。

  4. ネストされたレイアウト:
    サブディレクトリにlayoutファイルを配置することで、特定のルートセグメントに対してネストされたレイアウトを作成できます。

  5. 状態の保持:
    レイアウトコンポーネントは、ページ間のナビゲーション時に再レンダリングされず、状態を保持します。

  6. メタデータの設定:
    `metadata`エクスポートを使用して、SEOに重要なメタタグを設定できます。

  7. プロバイダーの設置:
    以前の`_app.js`の役割を引き継ぎ、アプリケーション全体で使用するプロバイダー(例:ChakraUI)を設置する場所となります。

  8. childrenプロップの使用:
    `children`プロップを受け取り、それをレンダリングすることで、レイアウト内に動的なコンテンツを配置します。

これらの機能により、layoutファイルはアプリケーションの構造を定義し、共通のUI要素を効率的に管理する中心的な役割を果たします。

2.5 インポート文における@有無の違いは何ですか?

この2つのインポート文の違いは、モジュールの参照方法にあります。

  1. `@`から始まるインポート:

import { createServerClient, type CookieOptions } from '@supabase/ssr'

このインポートでは、`@`から始まるパスを使用しています。これは通常、npm パッケージをインポートする際に使用されます。`@supabase/ssr` は Supabase のサーバーサイドレンダリング (SSR) 用のパッケージです。

  1. `@`なしのインポート:

import { cookies } from 'next/headers'

このインポートでは、`@`なしのパスを使用しています。これは Next.js の内部モジュールをインポートする際の標準的な方法です。`next/headers` は Next.js が提供する組み込みモジュールです。

主な違いは以下の通りです:

  1. 外部パッケージ vs 内部モジュール:

    • `@supabase/ssr` は外部の npm パッケージです。

    • `next/headers` は Next.js フレームワークの一部として提供される内部モジュールです。

  2. パスの記法:

    • `@`から始まるパスは通常、スコープ付きパッケージや特定の命名規則に従うパッケージを示します。

    • `@`なしのパスは、フレームワークの内部モジュールや、`node_modules` 内の標準的なパッケージを示すことが多いです。

  3. インストール方法:

    • `@supabase/ssr` は通常 `npm install @supabase/ssr` のようにして別途インストールする必要があります。

    • `next/headers` は Next.js をインストールした時点で既に利用可能です。

これらの違いは主にパッケージの出所と、プロジェクト内での位置づけを示しています。コードの動作自体には直接影響しませんが、依存関係の管理や、どのモジュールがプロジェクトの一部で、どれが外部から取り込まれているかを理解する上で重要です。

2.6 .拡張子(tsx/.ts/.js/.jsx)ごとの役割と使い分けは?

  1. .js (JavaScript)

    • 純粋な JavaScript ファイルに使用されます。

    • Node.js のサーバーサイドスクリプトや、シンプルなフロントエンド JavaScript に適しています。

  2. .jsx (JavaScript XML)

    • React コンポーネントを含む JavaScript ファイルに使用されます。

    • JSX 構文(React の XML-like 構文)をサポートしています。

  3. .ts (TypeScript)

    • TypeScript ファイルに使用されます。

    • 静的型付けを行いたい場合や、大規模なアプリケーションの開発に適しています。

  4. .tsx (TypeScript XML)

    • TypeScript と JSX の両方をサポートするファイルに使用されます。

    • React と TypeScript を組み合わせて使用する際に最適です。

推奨される使用方法:

  1. モダンな React プロジェクト:

    • `.tsx` を React コンポーネントに使用

    • `.ts` を非 React TypeScript ファイル(ユーティリティ、ヘルパー関数など)に使用

  2. TypeScript を使用しない React プロジェクト:

    • `.jsx` を React コンポーネントに使用

    • `.js` を非 React JavaScript ファイルに使用

  3. Node.js バックエンド:

    • TypeScript を使用する場合は `.ts`

    • JavaScript のみの場合は `.js`

  4. 静的型付けの重要性:

    • 大規模プロジェクトや長期的なメンテナンスが必要なプロジェクトでは、`.ts` や `.tsx` の使用が推奨されます。

    • 型安全性、コード補完、リファクタリングの容易さなどの利点があります。

  5. ブラウザ互換性:

    • `.js` ファイルは直接ブラウザで実行できます。

    • `.jsx`, `.ts`, `.tsx` ファイルはコンパイル/トランスパイルが必要です。

  6. プロジェクトの一貫性:

    • 一つのプロジェクト内では、可能な限り一貫した拡張子の使用が推奨されます。

最終的な選択は、プロジェクトの要件、チームの好み、使用するフレームワークやライブラリに依存します。多くのモダンな React プロジェクトでは、型安全性と JSX のサポートのために `.tsx` と `.ts` の使用が増えています。

2.7 middleware.tsの役割は?

middlewareの主な役割

  1. リクエストの前処理

    • サーバーがリクエストを処理する前に実行されます。

    • URLのパスやヘッダーを検査し、必要に応じて変更を加えることができます。

  2. 認証と認可

    • ユーザーの認証状態を確認し、適切なアクセス制御を行います。

    • 未認証ユーザーをログインページにリダイレクトするなどの処理が可能です。

  3. リダイレクトとリライト

    • 特定の条件下でURLのリダイレクトやリライトを行えます。

    • 例:古いURLを新しいURLにリダイレクトする。

  4. レスポンスヘッダーの操作

    • セキュリティヘッダーの追加や、キャッシュ制御などが可能です。

  5. ログ記録

    • リクエストの詳細をログに記録することができます。

middlewareの特徴

  • プロジェクトルートに配置

    • `middleware.ts`(または`.js`)ファイルをプロジェクトのルートディレクトリに配置します。

  • 全リクエストに適用

    • デフォルトでは全てのリクエストに対して実行されます。

    • `matcher`設定で特定のパスのみに適用することも可能です。

  • Edge Runtime

    • Middlewareは高速なEdge Runtimeで実行されます。

  • 早期実行

    • ページレンダリングやAPIルートの処理よりも先に実行されます。

  • 柔軟な条件分岐

    • リクエストの内容に基づいて様々な条件分岐が可能です。

middlewareを使用することで、アプリケーション全体に共通する処理を一元管理し、セキュリティや性能の向上、ルーティングの柔軟性を実現できます。

2.8 app/loginフォルダとapp/errorフォルダの役割は?

app/loginフォルダの役割

`app/login`フォルダは、ログイン機能に関連するコンポーネントとロジックを格納するためのディレクトリです。このフォルダ構造により、ログイン機能に関連するコードを整理し、管理しやすくなります。

page.tsx

`page.tsx`ファイルは、ログインページのUIを定義するコンポーネントです。主な役割は:

  • ログインフォームのレイアウトとデザインを定義

  • ユーザー入力(メールアドレス、パスワードなど)を受け取るフォームを提供

  • 必要に応じてクライアントサイドのバリデーションを実装

  • ログインアクションの呼び出し

action.ts

`action.ts`ファイルは、ログイン処理のロジックを含むサーバーアクションを定義します。主な役割は:

  • フォームから送信されたデータを受け取る

  • ユーザー認証のロジックを実装(例:データベースとの照合)

  • 認証結果に基づいてセッションの作成や更新を行う

  • 認証成功時のリダイレクト処理や、エラー時のメッセージ返却を行う

このファイルは、Next.jsのサーバーアクション機能を利用して、クライアントサイドから直接呼び出すことができるサーバーサイドの関数を定義します。

app/error/page.tsx

`app/error/page.tsx`ファイルは、アプリケーション全体のエラーハンドリングを担当します。主な役割は:

  • アプリケーション内で発生した予期せぬエラーをキャッチし表示する

  • ユーザーフレンドリーなエラーメッセージを提供する

  • 必要に応じてエラーの詳細情報を表示する

  • エラーからの回復オプション(ホームページへの戻るボタンなど)を提供する

このファイルは、Next.jsのエラーハンドリング機能と連携して動作し、アプリケーション全体のエラー状態を管理します。

これらのファイルとフォルダ構造を使用することで、ログイン機能とエラーハンドリングを効果的に実装し、アプリケーションの信頼性と使いやすさを向上させることができます。

2.9 ツールを使ったNext.jsプロジェクト作成と手動でファイルを作成した場合の違いは?

npx create-next-app -e with-supabase nextjs-supabase-auth

  • npx: Node.jsのパッケージランナーで、インストールせずにパッケージを実行できます。

  • create-next-app: Next.jsの公式プロジェクト作成ツールです。

  • -e with-supabase:

    • -eは --example の省略形で、特定のテンプレート(例)を使用することを指定します。

    • with-supabase は、SupabaseとNext.jsを統合した公式のサンプルテンプレートです。

  • nextjs-supabase-auth: これは作成するプロジェクトの名前です。

手動で作成した場合との違い:

  1. 構造と一貫性:

    • `create-next-app` を使用すると、一貫した構造とベストプラクティスに基づいたプロジェクトが作成されます。

    • 手動の場合、構造が不完全だったり、一貫性がなかったりする可能性があります。

  2. 依存関係:

    • `create-next-app` は必要な依存関係を自動的にインストールします。

    • 手動の場合、必要なパッケージを個別にインストールする必要があります。

  3. 設定ファイル:

    • `create-next-app` は `next.config.js`, `tsconfig.json` などの設定ファイルを自動生成します。

    • 手動の場合、これらの設定ファイルを自分で作成し、適切に構成する必要があります。

  4. ボイラープレートコード:

    • テンプレートを使用すると(特に `-e with-supabase` の場合)、多くのボイラープレートコードが既に書かれています。

    • 手動の場合、これらのコードを自分で書く必要があります。

  5. 最新のプラクティス:

    • 公式ツールは常に最新のベストプラクティスに基づいてプロジェクトを生成します。

    • 手動の場合、最新のプラクティスを把握し、適用する必要があります。

  6. Supabase統合 (`with-supabase` の場合):

    • Supabaseとの統合が既に設定されており、認証やデータベース接続のコードが含まれています。

    • 手動の場合、これらの統合を一から実装する必要があります。

  7. TypeScript設定:

    • `create-next-app` はTypeScriptの使用を尋ね、選択した場合は適切に設定します。

    • 手動の場合、TypeScriptの設定を自分で行う必要があります。

結論として、`create-next-app` を使用すると、一貫した、最新のプラクティスに基づいたプロジェクト構造が得られ、多くの初期設定の手間を省くことができます。特に `-e with-supabase` オプションを使用すると、Supabaseとの統合が既に行われているため、開発をより迅速に開始できます。手動で同じ構造を作成することは可能ですが、時間がかかり、エラーが発生しやすくなります。

2.10 起動コマンド`npm run dev`について

`npm run dev` コマンドは、Node.jsプロジェクト、特にNext.jsなどのフロントエンドフレームワークを使用したプロジェクトで非常によく使われるコマンドです。このコマンドの詳細と機能について説明します。

コマンドの構造:

  • `npm`: Node.jsのパッケージ管理ツールです。

  • `run`: npmスクリプトを実行するためのnpmのサブコマンドです。

  • `dev`: package.jsonファイル内のscriptsセクションで定義されたスクリプト名です。

package.json:

{
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
}
}

この例では、`npm run dev` は実際には `next dev` コマンドを実行します。

Next.jsでの動作:
Next.jsプロジェクトでは、`npm run dev` は以下の動作を行います:

  • 開発サーバーを起動(デフォルトではlocalhost:3000)

  • ファイルの変更を監視し、変更があればホットリロード

  • 開発モードでのビルド(最適化されていない、より速いビルド)

類似コマンド:
- `npm run build`: 本番用にプロジェクトをビルドします。
- `npm run start`: ビルドされたアプリケーションを起動します(本番モード)。

カスタマイズ:
package.jsonのscriptsセクションを編集することで、`dev`スクリプトをカスタマイズできます。例えば、
"dev": "next dev -p 4000"
これにより、開発サーバーがポート4000で起動します。

この記事が気に入ったらサポートをしてみませんか?