SEの部屋

ディレクトリ構成と役割について

はじめに

Next.jsはReactをベースにしたフレームワークです。このフレームワークの特徴の一つは、ディレクトリ構成が決まっていることです。例えば、ページを表示するためのコンポーネントは/pagesディレクトリに置かれますし、画像やCSSファイルなど、静的なファイルは/publicディレクトリに置かれます。このように、どのファイルがどこのディレクトリにあるのかが決まっているので、開発するときに迷うことがありません。
また、Next.jsはサーバーサイドレンダリングをサポートしているので、ページの表示が速くなり、SEOにも良い影響を与えます。さらに、ホットリロード機能を備えているので、開発者がコードを修正するたびに、変更をすぐに反映させることができます。これにより、コードを書いているときに、手間をかけずにアプリケーションの変更を確認することができます。

ディレクトリと構成

下記の例では、TypeScriptを使用して開発する場合、pagesディレクトリ内のファイル拡張子は .tsx になります。また、componentsディレクトリ内のコンポーネントは独自のスタイルを持つことができるため、CSSファイルも含まれています。libディレクトリ内には、API呼び出しやFirebaseなどの共通のロジックが含まれることがあります。publicディレクトリには、画像、スタイルシート、およびその他のパブリックファイルが含まれます。

├── pages/
│   ├── api/
│   │   └── [slug].ts
│   ├── _app.tsx
│   ├── _document.tsx
│   ├── index.tsx
│   └── about/
│       ├── index.tsx
│       └── team.tsx
├── components/
│   ├── Button/
│   │   ├── index.tsx
│   │   └── styles.module.css
│   ├── Layout/
│   │   ├── index.tsx
│   │   └── styles.module.css
│   └── ...
├── lib/
│   ├── api.ts
│   ├── firebase.ts
│   └── ...
├── public/
│   ├── images/
│   │   ├── logo.png
│   │   └── ...
│   ├── styles/
│   │   ├── global.css
│   │   └── ...
│   └── ...
├── styles/
│   ├── global.css
│   └── ...
├── types/
│   ├── index.d.ts
│   └── ...
├── utils/
│   ├── auth.ts
│   ├── constants.ts
│   └── ...
├── .eslintrc.json
├── .gitignore
├── next-env.d.ts
├── package.json
├── tsconfig.json
└── README.md

ディレクトリ構成の役割

/pages

/pagesディレクトリには、アプリケーションのルートURLに対応するReactコンポーネントが含まれています。つまり、/pages/index.tsxは、アプリケーションのルートURLに対応します。/pages/about.tsxは、/aboutに対応し、/pages/posts/[id].tsx/posts/:idに対応します。
Pagesディレクトリ内にある各コンポーネントは、Reactコンポーネントとして作成されます。そのため、通常のReactアプリケーションと同様に、TSXを使用してUIを定義することができます。ただし、Next.jsには特別なコンポーネントもあります。例えば、app.tsxerror.tsxは、アプリケーション全体のレイアウトやエラーページをカスタマイズするために使用されます。
Pagesディレクトリに含まれるReactコンポーネントは、Next.jsアプリケーションの開発プロセスで非常に重要な役割を果たします。新しいページを追加する場合は、単に新しいReactコンポーネントを/pagesディレクトリに作成するだけで、自動的に新しいページが作成されます。また、動的ルーティングを実装する場合は、/pagesディレクトリ内にダイナミックなルートを表すファイル名を作成することで実現できます。Pagesディレクトリの役割を理解することで、Next.jsアプリケーションの開発がより効率的に行えるようになります。
Pagesディレクトリは、アプリケーションの開発において非常に重要であるため、より深い理解が必要です。例えば、新しいページを作成する場合は、Reactコンポーネントを作成することができます。また、動的ルーティングを実装する場合は、/pagesディレクトリ内にダイナミックなルートを表すファイル名を作成することで実現できます。Pagesディレクトリには、アプリケーションのルートURLに対応するReactコンポーネントが含まれているため、アプリケーションの動作を理解する上で非常に重要です。

静的なページの作成

/pagesディレクトリにある.tsxファイルを使用することで、静的なページを簡単に作成できます。例えば、/pages/about.tsxファイルを作成することで、ウェブアプリケーションの「About」ページを作成できます。

// pages/about.tsx

import React from 'react';

const AboutPage = () => {
  return (
    <div>
      <h1>About Us</h1>
      <p>We are a company that specializes in creating amazing websites.</p>
    </div>
  );
};

export default AboutPage;

このファイルを作成することで、ウェブアプリケーションの/aboutページにアクセスすると、このコンポーネントがレンダリングされます。
このように、Reactを使用することで、ウェブアプリケーションの作成が容易になります。Reactには多くの機能があり、多くの開発者にとって、フロントエンド開発をする上でのベストな選択肢となっています。

動的なページの作成

/pagesディレクトリにある動的なページを作成することもできます。動的なページを作成するには、[slug].tsxという名前のファイルを作成します。例えば、/pages/blog/[slug].tsxファイルを作成することで、ウェブアプリケーションのブログページを作成できます。

// pages/blog/[slug].tsx

import React from 'react';
import { useRouter } from 'next/router';

const BlogPage = () => {
  const router = useRouter();
  const { slug } = router.query;

  return (
    <div>
      <h1>{slug}</h1>
      <p>This is the blog post with the slug {slug}.</p>
    </div>
  );
};

export default BlogPage;

このファイルを作成することで、ウェブアプリケーションの/blog/xxxページにアクセスすると、このコンポーネントがレンダリングされ、slugという変数にURLのxxx部分が格納されます。

エラーページの作成

/pagesディレクトリにあるエラーページを作成することもできます。エラーページを作成するには、error.tsxという名前のファイルを作成します。例えば、/pages/error.tsxファイルを作成することで、ウェブアプリケーションのエラーページをカスタマイズできます。

// pages/_error.tsx

import React from 'react';

const ErrorPage = ({ statusCode }) => {
  return (
    <div>
      <h1>{statusCode} - Error</h1>
      <p>Sorry, an error occurred.</p>
    </div>
  );
};

ErrorPage.getInitialProps = ({ res, err }) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : 404;
  return { statusCode };
};

export default ErrorPage;


/public

Next.jsのPublicディレクトリは、アプリケーションで使用される静的ファイルを保存するためのディレクトリです。Publicディレクトリに配置されたファイルは、ブラウザから直接アクセスできます。
Publicディレクトリに配置できるファイルには、画像、CSS、JavaScript、フォントなどがあります。これらのファイルは、アプリケーション内で相対パスを使用して参照することができます。例えば、/public/images/logo.pngというパスでアクセスすることができます。
Next.jsは、Publicディレクトリ内に配置されたファイルを自動的に最適化します。これにより、ファイルサイズを小さくし、読み込み速度を高速化することができます。また、Next.jsは、Publicディレクトリ内にあるファイルを自動的にURLプレフィックスにマッピングします。例えば、/public/images/logo.pngファイルは、/images/logo.pngとしてブラウザに表示されます。
Publicディレクトリには、アプリケーションに必要な静的ファイルを配置することができます。このディレクトリを使用することで、アプリケーションのビルドサイズを縮小し、パフォーマンスを向上させることができます。

画像の表示

/publicディレクトリに画像を配置し、次のようにimgタグを使用して表示できます。

// pages/index.tsx

import React from 'react';

const HomePage = () => {
  return (
    <div>
      <h1>Welcome to my website!</h1>
      <img src="/images/logo.png" alt="Logo" />
    </div>
  );
};

export default HomePage;

このように、imgタグで/publicディレクトリの画像を参照することができます。

CSSの使用

/publicディレクトリにCSSファイルを配置し、次のようにlinkタグを使用して使用することができます。

// pages/index.tsx

import React from 'react';

const HomePage = () => {
  return (
    <div>
      <h1>Welcome to my website!</h1>
      <link rel="stylesheet" href="/styles.css" />
      <p>This is some text styled with CSS.</p>
    </div>
  );
};

export default HomePage;

このように、linkタグで/publicディレクトリのCSSファイルを参照することができます。

JavaScriptの使用

/publicディレクトリにJavaScriptファイルを配置し、次のようにscriptタグを使用して使用することができます。

// pages/index.tsx

import React from 'react';

const HomePage = () => {
  return (
    <div>
      <h1>Welcome to my website!</h1>
      <script src="/script.js"></script>
    </div>
  );
};

export default HomePage;

このように、scriptタグで/publicディレクトリのJavaScriptファイルを参照することができます。

/components

Next.jsのComponentsディレクトリは、再利用可能なReactコンポーネントを保存するためのディレクトリです。このディレクトリは、UIの一部を表すコンポーネントを作成するために使用されます。
Componentsディレクトリには、アプリケーション内で使用されるReactコンポーネントを保存することができます。これらのコンポーネントは、他のコンポーネントやページからインポートされて再利用されることがあります。例えば、HeaderFooterButtonFormなどのコンポーネントがあります。
Next.jsのComponentsディレクトリは、UIをモジュール化し、コードの再利用性を高めることができます。また、コンポーネントを個別のファイルに保存することで、コードの見通しや保守性を向上させることができます。
Componentsディレクトリに保存されたコンポーネントは、import文を使用して他のコンポーネントやページから参照することができます。コンポーネントをimportすることで、そのコンポーネントを再利用することができます。このディレクトリを使用することで、アプリケーションの開発効率を向上させることができます。

ボタンコンポーネント

/components/Button.tsxという名前のファイルを作成し、次のようなコードを記述します。

// components/Button.tsx

import React from 'react';

type ButtonProps = {
  onClick: () => void;
  label: string;
};

const Button: React.FC<ButtonProps> = ({ onClick, label }) => {
  return (
    <button onClick={onClick}>
      {label}
    </button>
  );
};

export default Button;

このButtonコンポーネントは、onClickイベントとラベルの表示を受け取ります。これは、ページ内で再利用可能なボタンを作成するために使用されます。

ヘッダーコンポーネント

/components/Header.tsxという名前のファイルを作成し、次のようなコードを記述します。

// components/Header.tsx

import React from 'react';
import Link from 'next/link';

const Header: React.FC = () => {
  return (
    <header>
      <nav>
        <ul>
          <li>
            <Link href="/">
              <a>Home</a>
            </Link>
          </li>
          <li>
            <Link href="/about">
              <a>About</a>
            </Link>
          </li>
        </ul>
      </nav>
    </header>
  );
};

export default Header;

このHeaderコンポーネントは、ナビゲーションを表示するために使用されます。Linkコンポーネントを使用して、次のページに移動するためのリンクを作成することができます。

これらの例から、/componentsディレクトリは再利用可能なコンポーネントを作成するためのものであることがわかります。これにより、開発時間を節約し、コードの保守性と再利用性を高めることができます。

/styles

Next.jsのStylesディレクトリは、アプリケーションのスタイルを保存するためのディレクトリです。このディレクトリには、CSS、Sass、Lessなどのスタイルシートファイルを保存することができます。
Stylesディレクトリには、グローバルなスタイル、コンポーネント固有のスタイル、ページ固有のスタイルなど、アプリケーション内のさまざまな場所で使用されるスタイルを保存することができます。これらのスタイルシートは、CSS modulesを使用して、各コンポーネントまたはページごとにスコープ化されます。CSS modulesを使用することで、コンポーネントやページのスタイルが他の部分に影響を与えることがなくなり、スタイルの予期しない上書きや競合を回避できます。
Stylesディレクトリは、CSSファイルやSassファイル、Lessファイルなどのスタイルシートを保存するための推奨されるディレクトリです。また、Tailwind CSSやStyled Componentsなどのライブラリを使用する場合は、それらのスタイルシートもStylesディレクトリに保存することができます。
Next.jsのStylesディレクトリを使用することで、アプリケーションのスタイルを一元化し、コードの見通しや保守性を向上させることができます。また、スタイルを独立したファイルとして保存することで、開発効率も向上させることができます。

グローバルCSS

/styles/globals.cssという名前のファイルを作成し、次のようなコードを記述します。

/* styles/globals.css */

html,
body {
  padding: 0;
  margin: 0;
  font-family: 'Roboto', sans-serif;
  font-size: 16px;
}

a {
  color: blue;
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

このグローバルCSSは、すべてのページで適用されます。HTML要素、リンクのスタイルなど、アプリケーション全体に影響を与えるスタイルを定義することができます。

コンポーネント固有のCSS

/components/Button.module.cssという名前のファイルを作成し、次のようなコードを記述します。

/* components/Button.module.css */

.button {
  display: inline-block;
  background-color: blue;
  color: white;
  padding: 8px 16px;
  border-radius: 4px;
  cursor: pointer;
}

.button:hover {
  background-color: navy;
}

このCSSモジュールは、Buttonコンポーネントに固有のスタイルを定義します。CSS Modulesを使用すると、コンポーネントのスコープ内でクラス名を生成し、スタイルの衝突を回避することができます。
これらの例から、/stylesディレクトリはアプリケーションのスタイルを管理するために使用されることがわかります。グローバルCSSやコンポーネント固有のCSSなど、さまざまなスタイルを定義することができ、Next.jsのスタイル機能を活用することで、スタイルの管理が簡単になります。

/pages/api

Next.jsのApiディレクトリは、サーバーレス関数を作成するためのディレクトリです。このディレクトリにAPIエンドポイントを定義することで、サーバーレス関数を作成し、データベースや外部APIからデータを取得し、クライアント側にデータを提供することができます。
APIディレクトリは、サーバーサイドでのみ実行されるコードを含むことができ、クライアントサイドで実行されることはありません。このため、APIディレクトリに含まれるコードは、セキュリティ上の問題に対する対策を考慮する必要があります。
APIディレクトリには、一般的にREST APIやGraphQL APIなどのエンドポイントを定義するために、Node.jsのExpressやFastifyなどのWebフレームワークを使用します。また、Next.jsでは、APIルートのエンドポイントを自動的に作成するAPIルートファイルを使用することもできます。これにより、APIルートファイル内でエンドポイントを定義することができ、サーバーレス関数を簡単に作成することができます。
APIディレクトリを使用することで、アプリケーションのバックエンド機能を簡単に作成し、管理することができます。また、APIディレクトリ内でコードを分割することで、コードの見通しや保守性を向上させることができます。

データベースからデータを取得するAPI

/pages/api/posts.tsという名前のファイルを作成し、次のようなコードを記述します。

/* pages/api/posts.ts */

import type { NextApiRequest, NextApiResponse } from 'next';
import { connectToDatabase } from '../../utils/db';

export default async function handler(
  req: NextApiRequest,
  res: NextApiResponse
) {
  const db = await connectToDatabase();
  const posts = await db.collection('posts').find().toArray();

  res.status(200).json(posts);
}

このAPIは、MongoDBデータベースからすべての投稿を取得し、JSONレスポンスとして返します。connectToDatabase関数は、データベースに接続するためのユーティリティ関数であり、他のファイルで再利用できます。
このAPIエンドポイントには、/api/postsというエンドポイントが割り当てられ、HTTPリクエストを送信することで、投稿のリストを取得できます。

GET /api/posts

/pages/apiディレクトリを使用すると、サーバーレス関数を簡単に定義できます。データベースからのデータの取得、外部APIとの通信、ユーザー認証など、様々なサーバーレスのタスクを処理することができます。

/lib

Next.jsのLibディレクトリは、アプリケーション全体で使用される共通コードを配置するディレクトリです。このディレクトリには、ユーティリティ関数ヘルパー関数定数型定義などが含まれることがあります。
Libディレクトリは、PagesディレクトリやComponentsディレクトリのような特定の機能に依存しないため、アプリケーション全体で使用されるコードを格納するのに適しています。このため、Libディレクトリに含まれるコードは、アプリケーションのロジックを共通化することができます。
Libディレクトリに含まれるコードは、機能ごとにファイルを分割することができます。これにより、コードの再利用性を高め、保守性を向上させることができます。
また、Libディレクトリには、サードパーティライブラリやフレームワークなどの外部モジュールを含めることもできます。これにより、アプリケーションで使用する外部モジュールを一元管理することができます。
Libディレクトリは、アプリケーションの構造をより明確にし、コードの見通しや保守性を向上させることができます。

日付操作関連のユーティリティ関数

/lib/dateUtils.tsというファイルを作成し、次のようなコードを記述します。

/* lib/dateUtils.ts */

export function formatDate(date: Date) {
  const year = date.getFullYear();
  const month = date.getMonth() + 1;
  const day = date.getDate();

  return `${year}-${month < 10 ? '0' + month : month}-${
    day < 10 ? '0' + day : day
  }`;
}

export function getCurrentDate() {
  return formatDate(new Date());
}

このユーティリティファイルは、現在の日付を取得する関数getCurrentDateと、日付をYYYY-MM-DD形式にフォーマットする関数formatDateをエクスポートします。これらの関数は、アプリ内のさまざまな場所で使用される可能性があるため、共通の場所に保存することが推奨されます。

このように、/libディレクトリを使用すると、アプリケーション全体で使用される共通の関数やライブラリを保存できます。これにより、コードの再利用性が向上し、アプリケーションの保守性が向上します。

/node_modules

Next.jsのnode_modulesディレクトリは、アプリケーションの依存関係であるnpmパッケージがインストールされる場所です。Next.jsアプリケーションを開発するには、まずNode.jsをインストールし、npmパッケージを使用して必要なモジュールをインストールする必要があります。npmパッケージをインストールすると、パッケージの依存関係も自動的にインストールされ、node_modulesディレクトリに格納されます。
node_modulesディレクトリには、アプリケーションで使用される各種のnpmパッケージが含まれます。これらのパッケージは、アプリケーションの実行時に自動的にロードされます。このディレクトリは、アプリケーションの依存関係が自動的に管理されるため、開発者が手動で依存関係を管理する必要がありません。
node_modulesディレクトリは、アプリケーションの構造を明確にするために使用されるわけではありませんが、アプリケーションの動作にとって非常に重要なディレクトリです。必要なnpmパッケージをインストールすることで、アプリケーションに必要な機能を追加することができます。また、npmパッケージは定期的に更新されるため、アプリケーションのセキュリティを確保するためにも、node_modulesディレクトリの適切な管理が必要です。

/types

Next.jsのtypesディレクトリは、TypeScriptによる型定義ファイルを格納する場所です。TypeScriptは、JavaScriptに静的型付けを導入することで、より信頼性の高いコードを書くことができるようになります。Next.jsでもTypeScriptをサポートしており、アプリケーションの型定義を行うためにtypesディレクトリを使用することができます。
typesディレクトリには、アプリケーションで使用される各種の型定義ファイルを格納することができます。たとえば、Next.jsが提供するコンポーネントの型定義ファイルであるnext.d.tsや、外部ライブラリの型定義ファイルである@types/パッケージ名などがあります。これらの型定義ファイルをインポートすることで、アプリケーションで使用される各種のオブジェクトや関数に対して、適切な型付けを行うことができます。
また、typesディレクトリには、アプリケーション独自の型定義ファイルを格納することもできます。これらの型定義ファイルを使用することで、アプリケーションの独自の型を定義し、より正確な型付けを行うことができます。
typesディレクトリは、アプリケーションの動作に直接影響を与えるわけではありませんが、アプリケーションの信頼性や保守性を向上させるために重要なディレクトリです。適切に型定義ファイルを管理することで、コードの品質を維持し、開発効率を向上させることができます。

外部APIのレスポンスの型定義

外部APIから取得したデータを扱う場合、そのデータの型定義が必要になります。/typesディレクトリに、外部APIから取得するデータの型定義ファイルを保存することができます。
たとえば、次のような外部APIからのレスポンスがあるとします。

{
  "id": 1,
  "name": "John",
  "email": "john@example.com"
}

このレスポンスの型定義を/typings/user.tsというファイルに記述すると、次のようになります。

/* /types/user.ts */

export interface User {
  id: number;
  name: string;
  email: string;
}

このように、外部APIから取得したデータの型定義を/typesディレクトリに保存することで、コード内で正しい型を使用していることを保証できます。これにより、コードの可読性と保守性が向上し、開発効率が向上します。