Next.js 14 大型專案目錄配置及檔案配置


前言

嘿,夥伴們!如果你剛剛開始學習 Next.js 14 或者已經是個老手,但想優化你的專案目錄結構,那這篇文章絕對是你需要的。我們會詳細介紹 Next.js 14 推薦的專案目錄結構,並解釋一些特殊檔案的用途。準備好了嗎?讓我們開始吧!

為什麼要重視專案目錄結構?

在一個大型專案中,良好的目錄結構和檔案管理是成功的關鍵之一。它不僅能幫助你保持代碼的清晰和可維護性,還能讓團隊成員更容易地理解和協作。當你的專案變得越來越複雜,井然有序的目錄結構能夠大大提高開發效率,減少出錯的可能性。

大型專案目錄結構

大型專案需要更嚴謹的目錄結構來保持代碼的可維護性和可擴展性。以下是一個推薦的目錄結構範例,適用於 Next.js 14 的最新功能:

my-nextjs-large-app/
│
├── public/
│   └── images/
│       ├── logos/
│       │   ├── logo.png
│       └── icons/
│           └── favicon.ico
│
├── app/
│   ├── layout.tsx
│   ├── page.tsx
│   └── styles/
│       ├── globals.css
│       ├── reset.css
│       └── themes/
│           └── dark.css
│
├── components/
│   ├── common/
│   │   ├── Button.tsx
│   │   ├── Input.tsx
│   │   └── Modal.tsx
│   ├── layout/
│   │   ├── Header.tsx
│   │   ├── Footer.tsx
│   │   └── Sidebar.tsx
│   └── specific/
│       ├── DashboardWidget.tsx
│       └── UserProfileCard.tsx
│
├── contexts/
│   └── AuthContext.tsx
│
├── hooks/
│   ├── useAuth.ts
│   └── useFetch.ts
│
├── services/
│   ├── apiService.ts
│   ├── authService.ts
│   └── dataService.ts
│
├── store/
│   ├── index.ts
│   └── reducers/
│       └── userReducer.ts
│
├── styles/
│   ├── Home.module.css
│   ├── Dashboard.module.css
│   └── variables.css
│
├── utils/
│   ├── constants.ts
│   └── helperFunctions.ts
│
├── .eslintrc.json
├── .gitignore
├── next.config.mjs
├── package.json
└── README.md

目錄與檔案詳細說明

public/

這個目錄是放置靜態資源的地方,包括圖片、圖標等。大型專案通常會有更多的資源,因此我們可以進一步組織這些資源,例如將 logosicons 分別存放在子目錄中。這樣可以讓我們更容易地找到和管理這些靜態資源。

app/

app 目錄是 Next.js 14 中的重要更新,旨在更好地組織應用的佈局和全域樣式:

  • layout.tsx:負責定義應用的基本佈局,包括導航欄、頁腳等常見的結構元件。這個文件允許我們在應用的所有頁面之間共享佈局。
  • page.tsx:定義主要頁面的內容和邏輯,是整個應用的核心頁面文件。
  • styles/:包含全域樣式文件,如 globals.css,以及重置樣式的 reset.css,還有不同主題的樣式文件(例如 themes/dark.css)。

這樣的結構使得應用的佈局和主要頁面邏輯分離,從而提高代碼的可維護性和可讀性。

components/

components 目錄存放所有的可重用元件,分為 commonlayoutspecific 三個子目錄:

  • common/:存放可重用的基本元件,如按鈕、輸入框、模態框等。
  • layout/:包含佈局相關的元件,如頭部、底部和側邊欄。
  • specific/:包含特定功能的元件,如儀表板小部件和用戶資料卡。

這樣的分類可以使元件管理更加清晰,並且方便在不同頁面間重用。

contexts/

這個目錄存放 React Context 相關的文件,例如 AuthContext.tsx 用於管理身份驗證狀態。使用 Context API 可以有效地在應用中傳遞資料,避免層層傳遞的繁瑣。

hooks/

存放自定義的 Hook,如 useAuth.tsuseFetch.ts。自定義 Hook 可以將重複的邏輯抽取出來,使代碼更加簡潔和易於維護。

services/

存放與外部 API 或服務互動的邏輯。可以有多個服務文件,如 apiService.tsauthService.tsdataService.ts。集中管理 API 交互代碼可以保持代碼的一致性和可維護性。

例如,你可以這樣設置你的 API 服務:

// services/apiService.ts
export const fetchApi = async (url: string, options: RequestInit = {}) => {
  const response = await fetch(url, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

store/

如果使用 Redux 或其他狀態管理庫,這裡將包含狀態管理相關文件,如 index.tsreducers 目錄。

例如,你可以這樣設置你的 Redux store:

// store/index.ts
import { createStore, combineReducers } from 'redux';
import userReducer from './reducers/userReducer';

const rootReducer = combineReducers({
  user: userReducer,
  // 其他 reducers...
});

const store = createStore(rootReducer);

export default store;

這樣的結構可以使狀態管理邏輯清晰且易於擴展。

styles/

存放全域和模組專用的 CSS 文件。大型專案通常會有更多的樣式文件來管理不同的頁面和組件。

例如:

  • Home.module.css:首頁的樣式文件。
  • Dashboard.module.css:儀表板的樣式文件。
  • variables.css:存放全域的 CSS 變數。

這樣的結構有助於樣式管理的統一和維護。

utils/

存放實用的函數和輔助方法,如 constants.tshelperFunctions.ts

例如,在 constants.ts 中定義一些全域的常數:

// utils/constants.ts
export const API_BASE_URL = 'https://api.example.com';
export const DEFAULT_LANGUAGE = 'zh-TW';

helperFunctions.ts 中定義一些通用的輔助方法:

// utils/helperFunctions.ts
export const formatDate = (date: Date): string => {
  return new Date(date).toLocaleDateString('zh-TW');
};

export const capitalize = (str: string): string => {
  return str.charAt(0).toUpperCase() + str.slice(1);
};

這些工具函數可以在應用的多個部分中重複

使用,提升代碼的整潔度和效率。

根目錄檔案

  • .eslintrc.json:ESLint 設定文件,用於識別和修正 JavaScript 和 TypeScript 代碼中的問題。保持代碼的一致性和質量。
  • .gitignore:定義 Git 應忽略的文件和目錄,避免將不必要的文件推送到版本控制系統中。
  • next.config.mjs:用於自定義 Next.js 設定的文件。可以在這裡配置各種 Next.js 的設定選項。
  • package.json:包含專案的元數據,包括依賴和腳本。這是 npm 或 yarn 管理依賴的主要文件。
  • README.md:專案的概述文件,提供專案的基本資訊和說明。是一個專案的門面。

特殊檔案名稱解析

layout.tsxpage.tsx

這兩個文件位於 app/ 目錄中,是應用的核心文件。layout.tsx 負責定義應用的基本佈局,包括導航欄、頁腳等常見的結構元件。page.tsx 則負責頁面的主要內容和邏輯,是整個應用的核心頁面文件。

這兩個文件的存在,使得應用的佈局和主要頁面邏輯分離,從而提高代碼的可維護性和可讀性。

_app.tsx_document.tsx

這兩個文件位於 pages/ 目錄中,是 Next.js 應用的入口文件:

  • _app.tsx:用於定制應用的根組件,可以在這裡添加全域的 CSS 和狀態管理。它是每個頁面渲染的起點。
  • _document.tsx:用於定制 HTML 文檔結構,這個文件只會在服務器端渲染時使用。你可以在這裡添加自定義的 <html><body> 標籤,並且注入一些初始的 meta 信息。

這兩個文件的存在,使得我們可以對整個應用進行更細粒度的控制和自定義。

apiService.ts

這個文件位於 services/ 目錄中,負責處理與外部 API 的所有交互邏輯。集中管理 API 交互代碼有助於保持代碼的一致性和可維護性。

例如,你可以在這裡定義一個通用的 API 調用函數:

// services/apiService.ts
export const fetchApi = async (url: string, options: RequestInit = {}) => {
  const response = await fetch(url, {
    ...options,
    headers: {
      'Content-Type': 'application/json',
      ...options.headers,
    },
  });
  if (!response.ok) {
    throw new Error('Network response was not ok');
  }
  return response.json();
};

這樣,每次需要調用 API 時,你只需要使用 fetchApi 函數,這樣可以減少重複的代碼,提高代碼的可讀性和可維護性。

store/

這個目錄包含狀態管理的相關文件,index.ts 是主要的入口文件,而 reducers 目錄則包含各種狀態減速器(reducer),如 userReducer.ts

例如,你可以這樣設置你的 Redux store:

// store/index.ts
import { createStore, combineReducers } from 'redux';
import userReducer from './reducers/userReducer';

const rootReducer = combineReducers({
  user: userReducer,
  // 其他 reducers...
});

const store = createStore(rootReducer);

export default store;

這樣的結構可以使狀態管理邏輯清晰且易於擴展。

constants.tshelperFunctions.ts

這些文件位於 utils/ 目錄中,constants.ts 用於存放應用的常數,而 helperFunctions.ts 則存放各種實用的輔助方法。

例如,你可以在 constants.ts 中定義一些全域的常數:

// utils/constants.ts
export const API_BASE_URL = 'https://api.example.com';
export const DEFAULT_LANGUAGE = 'zh-TW';

helperFunctions.ts 中,你可以定義一些通用的輔助方法:

// utils/helperFunctions.ts
export const formatDate = (date: Date): string => {
  return new Date(date).toLocaleDateString('zh-TW');
};

export const capitalize = (str: string): string => {
  return str.charAt(0).toUpperCase() + str.slice(1);
};

這些工具函數可以在應用的多個部分中重複使用,提升代碼的整潔度和效率。

快速建立專案目錄的Shell Script

#!/bin/bash

# 創建專案目錄
mkdir my-nextjs-large-app
cd my-nextjs-large-app

# 初始化一個新的 Next.js 專案
npx create-next-app@latest . --typescript

# 安裝 Tailwind CSS
pnpm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p

# 創建必要的目錄
mkdir -p public/images/logos
mkdir -p public/images/icons
mkdir -p app/styles/themes
mkdir -p components/common
mkdir -p components/layout
mkdir -p components/specific
mkdir -p contexts
mkdir -p hooks
mkdir -p services
mkdir -p store/reducers
mkdir -p styles
mkdir -p utils

# 創建必要的文件
touch app/layout.tsx
touch app/page.tsx
touch app/styles/globals.css
touch app/styles/reset.css
touch app/styles/themes/dark.css
touch components/common/Button.tsx
touch components/common/Input.tsx
touch components/common/Modal.tsx
touch components/layout/Header.tsx
touch components/layout/Footer.tsx
touch components/layout/Sidebar.tsx
touch components/specific/DashboardWidget.tsx
touch components/specific/UserProfileCard.tsx
touch contexts/AuthContext.tsx
touch hooks/useAuth.ts
touch hooks/useFetch.ts
touch services/apiService.ts
touch services/authService.ts
touch services/dataService.ts
touch store/index.ts
touch store/reducers/userReducer.ts
touch styles/Home.module.css
touch styles/Dashboard.module.css
touch styles/variables.css
touch utils/constants.ts
touch utils/helperFunctions.ts

# 初始化 Tailwind CSS 配置
cat <<EOT > tailwind.config.js
module.exports = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],
  theme: {
    extend: {},
  },
  plugins: [],
}
EOT

# 創建 Tailwind CSS 入口文件
cat <<EOT > app/styles/tailwind.css
@tailwind base;
@tailwind components;
@tailwind utilities;
EOT

# 添加 Tailwind 到 globals.css
cat <<EOT > app/styles/globals.css
@import './tailwind.css';
EOT

# 更新 tsconfig.json 以包含 src
sed -i '' 's|"baseUrl": "./"|"baseUrl": "./src"|' tsconfig.json

# 創建預設頁面和組件
cat <<EOT > app/page.tsx
import { FC } from 'react';
import MainLayout from 'components/layout/MainLayout';

const Home: FC = () => {
  return (
    <MainLayout>
      <h1 className="text-3xl font-bold underline">
        Hello World
      </h1>
    </MainLayout>
  );
};

export default Home;
EOT

cat <<EOT > app/layout.tsx
import { FC, ReactNode } from 'react';

interface Props {
  children: ReactNode;
}

const MainLayout: FC<Props> = ({ children }) => {
  return (
    <div>
      <header>
        <h1>My Next App</h1>
      </header>
      <main>{children}</main>
      <footer>
        <p>© 2023 My Next App</p>
      </footer>
    </div>
  );
};

export default MainLayout;
EOT

結論

一個良好的目錄結構可以大大提升專案的可維護性和開發效率。希望這篇文章能幫助你理解如何組織一個大型的 Next.js 14 專案。如果你有任何問題或建議,歡迎在下方留言討論。祝你開發順利,Happy coding! 🎉


感謝閱讀,希望這篇文章對你有所幫助。