個人網頁開發
EP.03

認識 Next.js 專案結構
每個資料夾都有它的職責

打開 VS Code 看到一堆資料夾和檔案不知道從哪裡下手?
這篇帶你一個一個搞清楚它們的用途

Joseph Chen

2024
5 min read
1.2k views

EP.02 建好了專案,用 VS Code 打開之後,你看到的可能是這樣:

📁my-portfolio/
📁app/你 90% 的時間都在這裡
📁components/(需要自己建)可重用的 UI 元件
📁public/圖片、字型等靜態資源
📁node_modules/套件安裝位置,不需要動它
📄next.config.jsNext.js 設定檔
📄tailwind.config.tsTailwind CSS 設定
📄tsconfig.jsonTypeScript 設定
📄package.json套件清單與 npm scripts

看起來很複雜?其實你需要了解的只有幾個核心位置。這篇會從「最常用」的 app/ 開始, 然後介紹你的個人網頁實際用到的每一個部分。

app/ — 你的主戰場

App Router 的核心,所有頁面都在這裡

Next.js 14 開始採用 App Router:資料夾結構 = 路由(URL 路徑)。看一下我的個人網頁的 app/ 長什麼樣子:

📁app/
📄page.tsx首頁 → chullin.vercel.app/
📄layout.tsx全站共用的外殼(Navbar、Footer)
📄globals.css全域 CSS,設定字型、顏色等
📁blog/
📄page.tsx部落格列表頁 → /blog
📁leetcode-ep01-two-sum/
📄page.tsx→ /blog/leetcode-ep01-two-sum
📁projects/
📄page.tsx→ /projects
📁resume/
📄page.tsx→ /resume
📁contact/
📄page.tsx→ /contact

App Router 的核心規則

• 資料夾名稱 = URL 路徑的一段

• 每個資料夾裡的 page.tsx = 這個路徑的頁面

app/blog/page.tsx 對應 URL /blog

• 想新增一個頁面,建一個資料夾 + 在裡面放 page.tsx 就好

layout.tsx — 全站共用的外殼

layout.tsx 是一個特殊的檔案,它是所有頁面的「外殼」。 不管你去哪個 URL,layout 都會被套用。

我的個人網頁在 layout.tsx 裡放了 <Navbar /><Footer />, 所以每個頁面都自動有 Navbar 和 Footer,不需要每個頁面都加一次:

app/layout.tsx(簡化版)
export default function RootLayout({ children }) {
  return (
    <html lang="zh-Hant">
      <body>
        <Navbar />        {/* 每個頁面都有 Navbar */}
        <main>
          {children}    {/* 這裡才是各頁面的內容 */}
        </main>
        <Footer />        {/* 每個頁面都有 Footer */}
      </body>
    </html>
  );
}

{children} 是 React 的概念,代表「子頁面的內容」。 當你前往 /blog 時, children 就是 blog/page.tsx 的內容。

components/ — 可重用的 UI 元件

你自己寫的共用元件放這裡

components/ 資料夾是你自己建的(create-next-app 不會自動建), 用來放「多個頁面都會用到的」UI 元件。

📁components/
📄Navbar.tsx頂部導覽列,layout.tsx 引入它
📄Footer.tsx底部資訊列
📄ContactForm.tsx聯絡表單,contact 頁面引入它
元件 vs 頁面
  • 頁面(page.tsx):對應一個 URL,放在 app/ 下
  • 元件(component):可重用的 UI 積木,放在 components/
元件本身沒有 URL,它被頁面或 layout 引入使用。

以 Navbar 為例,它的程式碼大概長這樣:

components/Navbar.tsx(簡化版)
'use client';  // 這個元件要在瀏覽器執行(有互動)

import Link from 'next/link';
import { Button } from '@heroui/react';

export default function Navbar() {
  return (
    <nav className="fixed top-0 w-full z-50 bg-white/80 backdrop-blur">
      <div className="max-w-7xl mx-auto px-6 flex items-center justify-between h-16">
        <Link href="/" className="font-black text-xl">Joseph</Link>
        <div className="flex gap-4">
          <Link href="/blog">Blog</Link>
          <Link href="/projects">Projects</Link>
          <Link href="/resume">Resume</Link>
        </div>
      </div>
    </nav>
  );
}

public/ — 靜態資源

所有不需要被 JavaScript 處理的靜態檔案(圖片、PDF 履歷、robots.txt)都放在 public/

📁public/
📁assets/
📄profile.png個人照片
📄resume.pdfPDF 履歷
📄favicon.ico瀏覽器分頁的小圖示

public/ 裡的東西可以直接用 / 路徑存取。 例如 public/assets/profile.png 在程式碼裡用 /assets/profile.png 就能引用。

設定檔們

package.json整個專案的身份證

記錄: • 專案名稱、版本 • 所有依賴套件(dependencies) • npm scripts(dev、build、start) 你 npm install 過的套件都會記在這裡。

package.json
"scripts": {
  "dev": "next dev",   // npm run dev 啟動開發伺服器
  "build": "next build", // 打包產品版
  "start": "next start"  // 執行打包後的版本
}
tailwind.config.tsTailwind CSS 設定

最重要的設定是 content 陣列(告訴 Tailwind 要掃描哪些檔案),和 plugins(加入 HeroUI 的 Tailwind 支援)。

tailwind.config.ts
const config = {
  content: [
    "./app/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
    "./node_modules/@heroui/theme/dist/**/*.{js,ts}",
  ],
  plugins: [heroui()],
};
next.config.jsNext.js 設定

通常不需要動,但有些場景需要修改,例如允許外部圖片的域名(images.domains),或設定環境變數。

next.config.js
const nextConfig = {
  images: {
    domains: ['github.com'],  // 允許 GitHub 的圖片
  },
};

module.exports = nextConfig;
tsconfig.jsonTypeScript 設定

最常用到的是 paths 設定,讓你可以用 @ 代替繁瑣的相對路徑。例如 @/components/Navbar 而不是 ../../components/Navbar。

tsconfig.json
{
  "compilerOptions": {
    "paths": {
      "@/*": ["./*"]  // @ 代表專案根目錄
    }
  }
}

我的個人網頁完整結構

做為參考,以下是我的個人網頁(chullin.vercel.app)的 app/ 結構, 每個資料夾對應一個功能頁面:

📁app/
📄page.tsx首頁(自我介紹)
📄layout.tsx全站 Navbar + Footer
📄globals.css全域樣式
📁blog/部落格功能
📄page.tsx/blog — 文章列表
📁leetcode-ep01-two-sum/
📄page.tsx/blog/leetcode/ep01-two-sum
📁projects/作品集
📄page.tsx/projects
📁resume/履歷
📄page.tsx/resume
📁contact/聯絡表單
📄page.tsx/contact
📁flashcards/英文單字練習工具
📁snake/貪吃蛇遊戲(互動展示)
💡
為什麼有 flashcards 和 snake? 這些是「互動展示」頁面,展示我用 React 可以做出的互動功能。作品集不只有靜態頁面,這樣更有說服力。

實戰:新增一個「About」頁面

光看不如動手。用 3 個步驟新增一個 /about 頁面:

1

在 app/ 下建立 about/ 資料夾

terminal
mkdir app/about
2

在 about/ 裡新增 page.tsx

app/about/page.tsx
export default function AboutPage() {
  return (
    <div className="max-w-4xl mx-auto px-6 pt-24">
      <h1 className="text-5xl font-black">About Me</h1>
      <p className="text-gray-500 mt-4 text-xl">
        Hi, I'm Joseph Chen, a Software Engineer.
      </p>
    </div>
  );
}
3

打開瀏覽器前往 localhost:3000/about

你應該會看到「About Me」的標題。路由是自動建立的,不需要任何額外設定。

這就是 Next.js App Router 最直覺的地方:資料夾即路由。新增頁面只需要建資料夾 + 放 page.tsx,其他什麼都不用做。

這篇學到什麼

📁app/ 是主戰場,資料夾結構就是 URL 路徑,page.tsx 就是頁面
🏗️layout.tsx 是全站外殼,Navbar 和 Footer 只需要寫一次
🧩components/ 放可重用元件(Navbar、Footer),多頁面共用
🖼️public/ 放靜態資源(圖片、PDF),直接用 /filename 路徑引用
⚙️package.json(套件清單)、tailwind.config.ts(樣式設定)、tsconfig.json(路徑縮寫)
新增頁面:在 app/ 下建資料夾 + 放 page.tsx,一分鐘搞定
Web Dev
Next.js
App Router
專案結構
EP.03