Next.jsディレクトリのベストプラクティス
📌 ホームページ(Landing Page)のベストディレクトリ構成
目的
SEO & パフォーマンスを重視(SSR / ISR 活用)
軽量 & 高速(画像最適化、サーバー負荷削減)
デザイン & UX に優れた構成(TailwindCSS + shadcn/ui + Framer Motion)
技術要件:
✅ Next.js App Router(ページ & API 管理)
✅ TypeScript(型安全な開発)
✅ TailwindCSS(ユーティリティベースのデザイン)
✅ shadcn/ui(高品質な UI コンポーネント)
✅ Framer Motion(スムーズなアニメーション)
✅ Zod(型安全なバリデーション)
✅ Zustand(シンプルな状態管理)
✅ React Query(API キャッシュ & フェッチ管理)
✅ NextAuth.js(ユーザー認証)
✅ Sentry(エラーロギング & パフォーマンス監視)
📌 Next.js App Router を活用したスケーラブルなディレクトリ構成(Admin + Portfolio 対応)
この構成は、スケーラビリティ・拡張性・パフォーマンス最適化 を考慮した設計になっています。
components/sections/ → ページごとのセクションを整理
components/ui/ → ボタン・モーダル・トーストなどの共通コンポーネントを一元管理
app/admin/ → 管理者専用のダッシュボード & 記事・ユーザー管理
app/portfolio/ → 作品紹介ページ(動的ルーティング)
store/ → Zustand による状態管理
hooks/ → 再利用可能なカスタムフック
lib/ → API クライアント・認証処理・ユーティリティ関数
🚀 スケーラブルなディレクトリ構成
📦 my-project
├── 📂 app
│ ├── layout.tsx # ✅ 全体レイアウト
│ ├── page.tsx # ✅ ホームページ
│ ├── loading.tsx # ✅ ローディング画面
│ ├── not-found.tsx # ✅ 404 ページ
│ ├── error.tsx # ✅ エラーページ (Sentry 用)
│ ├── 📂 api # ✅ API エンドポイント
│ │ ├── auth/route.ts # 認証 API (NextAuth.js)
│ │ ├── contact/route.ts # お問い合わせフォーム API
│ │ ├── subscribe/route.ts # メール購読 API
│ │ ├── analytics/route.ts # アクセス解析 API
│ ├── 📂 blog # ✅ ブログページ
│ │ ├── page.tsx # ブログ一覧ページ
│ │ ├── [slug]/page.tsx # 記事詳細ページ
│ ├── 📂 portfolio # ✅ 作品紹介ページ(動的ルーティング)
│ │ ├── page.tsx # 作品一覧
│ │ ├── [slug]/page.tsx # 作品詳細ページ
│ ├── 📂 admin # ✅ 管理画面
│ │ ├── layout.tsx # 管理画面の共通レイアウト
│ │ ├── page.tsx # ダッシュボード
│ │ ├── 📂 articles # 記事管理
│ │ │ ├── page.tsx # 記事一覧
│ │ │ ├── new/page.tsx # 記事作成
│ │ │ ├── [id]/edit.tsx # 記事編集
│ │ ├── 📂 users # ユーザー管理
│ │ │ ├── page.tsx # ユーザー一覧
│ │ │ ├── [id]/edit.tsx # ユーザー編集
│ │ ├── 📂 portfolio # 作品管理
│ │ │ ├── page.tsx # 作品一覧
│ │ │ ├── new/page.tsx # 作品登録
│ │ │ ├── [id]/edit.tsx # 作品編集
├── 📂 components
│ ├── 📂 sections # ✅ 各セクションごとに整理
│ │ ├── Hero.tsx # ヒーローセクション
│ │ ├── About.tsx # 会社概要
│ │ ├── Services.tsx # サービス紹介
│ │ ├── Testimonials.tsx # お客様の声
│ │ ├── Pricing.tsx # 料金プラン
│ │ ├── Contact.tsx # お問い合わせ
│ │ ├── Portfolio.tsx # ポートフォリオ一覧
│ │ ├── FAQ.tsx # よくある質問
│ │ ├── Footer.tsx # フッター
│ ├── 📂 ui # ✅ 再利用可能な UI コンポーネント
│ │ ├── button.tsx # ボタン
│ │ ├── card.tsx # カードデザイン
│ │ ├── input.tsx # 入力フィールド
│ │ ├── navbar.tsx # ナビゲーションバー
│ │ ├── modal.tsx # モーダル
│ │ ├── pagination.tsx # ページネーション
│ │ ├── accordion.tsx # アコーディオン
│ │ ├── tabs.tsx # タブ切り替え
│ │ ├── toast.tsx # トースト通知
│ │ ├── skeleton.tsx # ローディングスケルトン
│ ├── 📂 layout # ✅ レイアウト関連
│ │ ├── header.tsx # ヘッダー
│ │ ├── sidebar.tsx # サイドバー
├── 📂 hooks # ✅ カスタムフック
│ ├── useAuth.ts # 認証情報取得
│ ├── useTheme.ts # ダークモード切り替え
│ ├── useScroll.ts # スクロールイベント処理
│ ├── useModal.ts # モーダルの開閉管理
├── 📂 store # ✅ Zustand を使った状態管理
│ ├── useAuthStore.ts # 認証管理
│ ├── useThemeStore.ts # テーマ管理
├── 📂 lib # ✅ ユーティリティ関数
│ ├── api.ts # API クライアント(React Query 用)
│ ├── auth.ts # 認証関連処理
│ ├── prisma.ts # Prisma クライアント設定
│ ├── cn.ts # clsx + tailwind-merge ヘルパー
├── 📂 styles # ✅ グローバルスタイル
│ ├── globals.css # TailwindCSS のグローバルスタイル
│ ├── tailwind.css # TailwindCSS の設定
├── 📂 public # ✅ 静的アセット
│ ├── images/ # 画像ファイル
│ │ ├── hero.webp
│ │ ├── logo.svg
│ ├── icons/ # アイコン
│ │ ├── facebook.svg
│ │ ├── instagram.svg
├── 📂 prisma # ✅ データベーススキーマ
│ ├── schema.prisma # Prisma のスキーマ定義
│ ├── seed.ts # 初期データ投入スクリプト
├── tailwind.config.ts # TailwindCSS 設定
├── next.config.js # Next.js 設定
├── tsconfig.json # TypeScript 設定
├── package.json # パッケージ管理
└── .eslintrc.js # ESLint 設定
✅ ポイント
🔥 Admin 機能強化(記事・ユーザー・ポートフォリオ管理)
🔥 NextAuth.js による認証(app/api/auth/route.ts)
🔥 Zustand + React Query で状態管理 & API キャッシュ
🔥 Sentry でエラーロギングを実装
📌 0 から作る最適な順番(Next.js App Router + TailwindCSS + Zustand + React Query)
この手順は、スケーラビリティ・メンテナンス性・パフォーマンス最適化 を考慮した、最も効率的な開発順序 です。
🚀 開発の最適なステップ
🟢 1️⃣ プロジェクトのセットアップ
まず、Next.js + TypeScript + TailwindCSS + shadcn/ui をセットアップ。
# 1. Next.js App Router プロジェクトを作成
npx create-next-app@latest my-project --typescript --tailwind --eslint --app
cd my-project
# 2. 必要なパッケージをインストール
npm install @tanstack/react-query zustand next-auth @auth/prisma-adapter \
@hookform/resolvers react-hook-form zod prisma @prisma/client \
@sentry/nextjs framer-motion clsx tailwind-merge
📌 インストールするもの:
✅ React Query(API キャッシュ & フェッチ管理)
✅ Zustand(状態管理)
✅ NextAuth.js(認証)
✅ Prisma(データベース ORM)
✅ Zod(バリデーション)
✅ Sentry(エラーロギング)
✅ Framer Motion(アニメーション)
✅ clsx & tailwind-merge(Tailwind クラス管理)
🟢 2️⃣ TailwindCSS & shadcn/ui のセットアップ
# 1. TailwindCSS の設定
npx tailwindcss init -p
📌 tailwind.config.ts を編集:
import { type Config } from "tailwindcss";
export default {
content: ["./app/**/*.{js,ts,jsx,tsx}", "./components/**/*.{js,ts,jsx,tsx}"],
theme: { extend: {} },
plugins: [],
} satisfies Config;
# 2. shadcn/ui の設定
npx shadcn-ui@latest init
🟢 3️⃣ ディレクトリ構成を作成
📌 mkdir コマンドで作成:
mkdir -p components/{ui,layout,sections} hooks store lib prisma public/images
mkdir -p app/{api,admin,portfolio,blog}
mkdir -p app/api/{auth,contact,subscribe,analytics}
mkdir -p app/admin/{articles,users,portfolio}
📌 フォルダの役割:
app/api/ → API ルート
components/ui/ → 共通 UI コンポーネント
components/layout/ → ヘッダー・フッター
components/sections/ → セクションごとのコンポーネント
store/ → Zustand による状態管理
hooks/ → カスタムフック
🟢 4️⃣ Prisma 設定
npx prisma init
📌 prisma/schema.prisma を編集:
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
model User {
id String @id @default(uuid())
email String @unique
password String?
name String?
articles Article[]
}
model Article {
id String @id @default(uuid())
title String
content String
authorId String
author User @relation(fields: [authorId], references: [id])
createdAt DateTime @default(now())
}
# マイグレーション & クライアント生成
npx prisma migrate dev --name init
npx prisma generate
🟢 5️⃣ Zustand で状態管理
📌 store/useAuthStore.ts
import { create } from "zustand";
interface AuthState {
user: { id: string; name: string } | null;
setUser: (user: AuthState["user"]) => void;
}
export const useAuthStore = create<AuthState>((set) => ({
user: null,
setUser: (user) => set({ user }),
}));
🟢 6️⃣ API 実装
📌 app/api/auth/route.ts
import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";
import { PrismaAdapter } from "@auth/prisma-adapter";
import { prisma } from "@/lib/prisma";
export default NextAuth({
adapter: PrismaAdapter(prisma),
providers: [
CredentialsProvider({
name: "Credentials",
credentials: { email: { label: "Email" }, password: { label: "Password" } },
async authorize(credentials) {
const user = await prisma.user.findUnique({ where: { email: credentials?.email } });
return user || null;
},
}),
],
});
🟢 7️⃣ ページ & セクションの作成
📌 components/sections/Hero.tsx
import { motion } from "framer-motion";
export default function Hero() {
return (
<motion.section
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
className="h-screen flex items-center justify-center bg-gray-900 text-white"
>
<h1 className="text-5xl font-bold">Welcome to My Landing Page</h1>
</motion.section>
);
}
📌 app/page.tsx
import Hero from "@/components/sections/Hero";
export default function HomePage() {
return <Hero />;
}
🟢 8️⃣ フォーム & バリデーション(Zod + React Hook Form)
📌 components/ui/form.tsx
import { useForm } from "react-hook-form";
import { z } from "zod";
import { zodResolver } from "@hookform/resolvers/zod";
import { Input } from "@/components/ui/input";
import { Button } from "@/components/ui/button";
const schema = z.object({
email: z.string().email("Invalid email"),
});
export default function ContactForm() {
const { register, handleSubmit, formState: { errors } } = useForm({
resolver: zodResolver(schema),
});
return (
<form onSubmit={handleSubmit(console.log)}>
<Input {...register("email")} placeholder="Email" />
{errors.email && <p>{errors.email.message}</p>}
<Button type="submit">Submit</Button>
</form>
);
}
🟢 9️⃣ デプロイ準備
# Vercel にデプロイ
npm run build
vercel deploy
✅ まとめ
💡 最適な開発順序
1️⃣ プロジェクトセットアップ(Next.js + Tailwind + shadcn/ui)
2️⃣ ディレクトリ構成の作成
3️⃣ Prisma 設定(データベース構築)
4️⃣ Zustand + API 実装(状態管理 & 認証)
5️⃣ ページ & セクション作成(UI & アニメーション)
6️⃣ フォーム & バリデーション(Zod + React Hook Form)
7️⃣ デプロイ(Vercel)