ディレクトリ構成と役割について
はじめに
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.tsx
とerror.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コンポーネントを保存することができます。これらのコンポーネントは、他のコンポーネントやページからインポートされて再利用されることがあります。例えば、Header
、Footer
、Button
、Form
などのコンポーネントがあります。
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
ディレクトリに保存することで、コード内で正しい型を使用していることを保証できます。これにより、コードの可読性と保守性が向上し、開発効率が向上します。