【Next】入門者必見!TypeScriptでNextアプリの環境構築と構造を理解する
今回は入門者必見!TypeScriptでNextアプリの環境構築と構造を理解するの紹介です。
- 1. Nextとは?
- 2. Reactとの違い
- 3. NextをAppを作成
- 3.1. Ok to proceed? (y)
- 3.2. Would you like to use ESLint?
- 3.3. Would you like to use Tailwind CSS?
- 3.4. Would you like your code inside a
src/
directory? - 3.5. Would you like to use App Router? (recommended)
- 3.6. Would you like to use Turbopack for next dev?
- 3.7. Would you like to customize the import alias (@/* by default)?
- 4. Nextアプリのプロジェクト構造
- 5. サンプルでHeaderやFooterを追加
Nextとは?
Next.jsとは、Reactをベースに開発されたフロントエンドフレームワークになります。
Reactとの違い
Next
- レンダリング方式
- サーバーサイドレンダリング(SSR)がデフォルト
- スタティックサイト生成(SSG)もサポート
- クライアントサイドも"use client"で使用可能
- ルーティング
- ファイルシステムベースのルーティング
- app/やpages/ディレクトリ構造でルーティング自動生成
- 動的ルーティングも簡単に実装可能
- 環境構築
- 開発に必要な機能が最初から組み込み
- 最小限の設定で開発開始可能
- データフェッチ
- サーバーコンポーネントでのデータフェッチ
- 自動的なキャッシュと再検証機能
- サーバーアクションでのフォーム処理
- パフォーマンス最適化
- 画像最適化機能が組み込み済み
- 自動コード分割
- フォント最適化
- ビルド時の自動最適化
React
- レンダリング方式
- クライアントサイドレンダリング(CSR)がデフォルト
- JavaScriptを使って、ブラウザ上でUIをレンダリング
- ルーティング
- デフォルトではルーティング機能なし
- React RouterなどのライブラリBを別途導入が必要
- 環境構築
- プロジェクト開始時に多くの設定が必要
- Webpack設定やその他機能を手動で設定
- データフェッチ
- useEffectやカスタムフックを使って実装
- 状態管理は別途ReduxやRecoilなどが必要
- パフォーマンス最適化
- 画像最適化、コード分割は手動実装が必要
- パフォーマンスチューニングは開発者次第
スポンサードサーチ
NextをAppを作成
ターミナルで次のコマンドをコピー&ペーストしてください。
「next-ts-app」はアプリ名になり「–typescript」はオプションでTypeScriptを指定しています。
npx create-next-app@latest next-ts-app --typescript
Ok to proceed? (y)
Ok to proceed? (y)
- プロジェクトの作成を続行してよいかの確認を行います。
- インストールされる依存関係(パッケージ)の確認します。
y または Enter: インストールを続行して、nでインストールをキャンセルします。
このときインストールされる主な依存関係は次になります(一例)
next
react
react-dom
typescript
@types/react
@types/node
Would you like to use ESLint?
Would you like to use ESLint
ESLint はJavaScript/TypeScriptのコード品質とスタイルをチェックするツールです。
Yes を選択することを推奨します。
ESLintの利点
- コードの一貫性を保つ
- バグの早期発見
- タイプミスの防止
- ベストプラクティスの強制
- チーム開発での品質維持
Would you like to use Tailwind CSS?
Would you like to use Tailwind CSS?
Tailwind CSSは、ユーティリティファーストのCSSフレームワークです。
YesにするとTailwind CSSがインストールされ、パッケージや設定ファイルが追加されます。
Noの場合は通常のCSSスタイリングのみが使用できます。
Would you like your code inside a src/
directory?
Would you like your code inside a `src/` directory?
プロジェクトに「src」ディレクトリを配置するかどうかの選択です。
Yesの場合
next-ts-app/
├── src/ # ソースコードはここに
│ ├── app/
│ ├── components/
│ ├── styles/
│ └── lib/
├── public/ # 静的ファイル
├── package.json
└── ...その他設定ファイル
srcディレクトリを使用するメリット
- コードの整理
- ソースコードとビルド設定を明確に分離
- プロジェクトルートがすっきりする
- 一般的な慣習
- 多くのReactプロジェクトで採用
- チーム開発で分かりやすい
Noの場合
next-ts-app/
├── app/
├── components/
├── styles/
├── lib/
├── public/
├── package.json
└── ...その他設定ファイル
srcディレクトリを使用するデメリット
- ルートディレクトリが混雑:
- ソースコードと設定ファイルが同じ階層に
- プロジェクトが大きくなると管理が難しい
- 非標準的
- モダンなReactプロジェクトではsrc/が一般的
- 他の開発者が混乱する可能性
Would you like to use App Router? (recommended)
Would you like to use App Router? (recommended)
App Router導入についてです。
App RouterはNext.js 13以降で導入された新しいルーティングシステムです。
端的に伝えると「フォルダとファイルでURLが決まる新しいルーティングシステム」です。
appフォルダ内のファイル構成がそのままURLに反映されます。
App Routeあり
src/
└── app/
├── page.tsx # トップページ (/)
├── about/ # アバウトページ (/about)
│ └── page.tsx
├── blog/ # ブログ一覧 (/blog)
│ ├── page.tsx
│ └── [id]/ # 個別記事 (/blog/1, /blog/2...)
│ └── page.tsx
└── layout.tsx # 全ページ共通のレイアウト
App Router初学者には複雑なのでディレクトリ、ファイルの使わかたを覚えておきましょう
App Routerを使う場合は次のようになっています
- pagesではなくappディレクトリを使用
- index.tsx → page.tsxを使用
- _app.tsx → layout.tsxを使用
- ファイル構造がそのままルーティングに(about.tsx → about/page.tsx)
- サーバーコンポーネントがデフォルト
- レイアウト、ローディング、エラーの扱いが直感的(layout.tsx, loading.tsx, error.tsx)
- データフェッチがより簡単に(.tsxファイル内で直接非同期処理が可能)
- より高速なパフォーマンス(サーバーサイドレンダリングの強化)
各ディレクトリやファイルの説明例になります。
- src/ :プロジェクトのソースコードを格納するルートディレクトリ
- app/ :Next.jsのApp Routerのルートディレクトリ
- page.tsx :トップページのコンテンツを表示するファイル (URLは /)
- about/ :アバウトページのディレクトリ (URLは /about)
- about/page.tsx :アバウトページのコンテンツを表示するファイル
- blog/ :ブログ関連ページのディレクトリ (URLは /blog)
- blog/page.tsx :ブログ一覧ページのコンテンツを表示するファイル
- blog/[id]/ :動的なブログ記事ページのディレクトリ ([id]は可変の値)
- blog/[id]/page.tsx :個別のブログ記事ページを表示するファイル (URLは /blog/1 など)
- layout.tsx :全ページで共通して使用されるレイアウトファイル(ヘッダー、フッターなど)
App Routeなし
src/
└── pages/
├── index.tsx # トップページ (/)
├── about.tsx # アバウトページ (/about)
├── blog/
│ ├── index.tsx # ブログ一覧ページ (/blog)
│ └── [id].tsx # 個別ブログ記事ページ (/blog/1 など)
└── _app.tsx # 全ページで共通して使用されるレイアウトファイル
App Routerを使わない場合は次のようになっています
- appがなくpagesディレクトリを使用
- page.tsx → index.tsx を使用
- layout.tsx → _app.tsx を使用
- ファイル名がそのままルーティングに(about/page.tsx → about.tsx)
Would you like to use Turbopack for next dev?
Would you like to use Turbopack for next dev?
Turbopackは、Next.jsの開発環境をより高速にするために作られた新しいバンドラーです。Webpackの後継として開発されており、Rustで書かれているため処理が非常に高速です。
ただし、現時点(2024年11月)ではベータ版であり機能が限定的で安定性に欠けるため、本番プロジェクトでの使用は推奨されません。
そのため、特に実験目的でない限り「No」を選択することをお勧めします。
Would you like to customize the import alias (@/* by default)?
Would you like to customize the import alias (@/* by default)?
インポートエイリアス(@/*)は、ファイルパスを簡潔に書くための機能です。「Yes」を推奨します。
エイリアスを使うと、相対パスで遡る必要がなく、コードが読みやすくなり保守性が高まります。
特に深い階層のファイルを参照する際に便利なため、「Yes」を選択することをお勧めします。
もし、パスについての概念の知識が浅く、理解を深めたいのであればNoでもいいと思います。
エイリアスあり
// エイリアスあり (Yes) - @がsrcディレクトリを指す
import { Button } from "@/components/Button"
import { getData } from "@/lib/getData"
エイリアスなし
// エイリアスなし (No)
import { Button } from "../../../components/Button"
import { getData } from "../../../../lib/getData"
Nextアプリのプロジェクト構造
├── public/ # 静的ファイルを格納するディレクトリ
│ ├── file.svg
│ ├── globe.svg
│ ├── next.svg
│ ├── vercel.svg
│ └── window.svg
├── src/ # ソースコードのメインディレクトリ
│ └── app/ # App Routerのルートディレクトリ
│ ├── favicon.ico # ファビコン
│ ├── fonts/ # フォントファイル
│ ├── globals.css # グローバルCSS
│ ├── layout.tsx # 共通レイアウト
│ └── page.tsx # トップページ
├── package.json # プロジェクトの依存関係と設定
├── postcss.config.mjs # PostCSSの設定ファイル
├── tailwind.config.ts # Tailwindの設定ファイル
└── tsconfig.json # TypeScriptの設定ファイル
public
静的ファイルを格納するディレクトリ
src
ソースコードのメインディレクトリ
package.json
プロジェクトの依存関係と設定
tsconfig.json
TypeScriptの設定ファイル
一番最初に呼ばれるファイル
src/app/layout.tsx
「src/app/layout.tsx」が一番最初に呼ばれるファイルです。
コメント入れて分かりやすくしています。
// フォントとメタデータの設定
import type { Metadata } from "next"; // メタデータの型定義をインポート
import localFont from "next/font/local"; // ローカルフォントを使用するための機能
import "./globals.css"; // グローバルCSSの読み込み
// カスタムフォントの設定
const geistSans = localFont({
src: "./fonts/GeistVF.woff", // サンセリフフォント
variable: "--font-geist-sans", // CSSカスタムプロパティ名
weight: "100 900", // フォントウェイトの範囲
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff", // 等幅フォント
variable: "--font-geist-mono",
weight: "100 900",
});
// サイトのメタデータ設定
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
// ルートレイアウト
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
// フォント変数とアンチエイリアスを適用
>
{children} {/* ここにpage.tsxの内容が自動的に挿入される */}
</body>
</html>
);
}
{children}でpage.tsxを読み込んでいます。
レンダリングすると次のようになります。
<!-- 実際のレンダリング結果 -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Create Next App</title>
<meta name="description" content="Generated by create next app">
<!-- Next.jsが自動的に追加するその他のメタタグやスタイル -->
</head>
<body class="__variable_20f6c2 __variable_daf498 antialiased">
<!-- geistSans.variable = __variable_20f6c2 -->
<!-- geistMono.variable = __variable_daf498 -->
<!-- ここにpage.tsxの内容が挿入される -->
<main>
<h1>Welcome to Next.js!</h1>
<!-- page.tsxのその他のコンテンツ -->
</main>
<!-- Next.jsが自動的に追加するスクリプト -->
</body>
</html>
- __variable_xxxxx クラスは、フォント変数のためにNext.jsが自動生成したユニークなクラス名
- antialiased クラスでフォントのアンチエイリアシングが適用
- ページコンテンツ(page.tsx)はタグ内に自動的に挿入される
- 必要なメタタグやスクリプトはNext.jsが自動的に追加
スポンサードサーチ
サンプルでHeaderやFooterを追加
先ほど学んだ、「一番最初に呼ばれるファイル」を参考に、
HeaderやFooterを追加した場合のtreeやlayout.tsxを見てみましょう
HeaderやFooterを追加した場合のディレクトリ構成
appディレクトリにコンポーネントディレクトリを作って、そこにHeaderやFooter用のファイルを作成します。
src/
└── app/
├── components/ #共通コンポーネント用ディレクトリ(新規作成)
│ ├── Header.tsx #ヘッダーコンポーネント(新規作成)
│ └── Footer.tsx #フッターコンポーネント(新規作成)
├── fonts/ #既存のフォントディレクトリ
│ ├── GeistVF.woff #既存
│ └── GeistMonoVF.woff #既存
├── favicon.ico #既存
├── globals.css #既存
├── layout.tsx #既存(Headerとfooterを追加)
└── page.tsx #既存
HeaderやFooterを追加した場合のlayout.tsx
作成したHeaderコンポーネントやFooterコンポーネントをlayout内で呼び出すことで、ファイルが読み込まれます。
import type { Metadata } from "next";
import localFont from "next/font/local";
import "./globals.css";
import Header from "./components/Header";
import Footer from "./components/Footer";
const geistSans = localFont({
src: "./fonts/GeistVF.woff",
variable: "--font-geist-sans",
weight: "100 900",
});
const geistMono = localFont({
src: "./fonts/GeistMonoVF.woff",
variable: "--font-geist-mono",
weight: "100 900",
});
export const metadata: Metadata = {
title: "Create Next App",
description: "Generated by create next app",
};
export default function RootLayout({
children,
}: Readonly<{
children: React.ReactNode;
}>) {
return (
<html lang="en">
<body
className={`${geistSans.variable} ${geistMono.variable} antialiased`}
>
<Header />
<main className="min-h-screen">
{children}
</main>
<Footer />
</body>
</html>
);
}
HeaderやFooterを追加した場合のレンダリング結果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Create Next App</title>
<meta name="description" content="Generated by create next app">
</head>
<body class="__variable_20f6c2 __variable_daf498 antialiased">
<!-- Header -->
<header>
<nav>
<!-- ヘッダーの内容 -->
</nav>
</header>
<!-- Main content -->
<main class="min-h-screen">
<!-- page.tsxの内容 -->
</main>
<!-- Footer -->
<footer>
<!-- フッターの内容 -->
</footer>
</body>
</html>