Next.js 自动生成项目的文件结构笔记

EN|ZH

  • 简介: 详细解读一个典型 Next.js 项目中的每个文件——它的作用、存在的原因、以及各文件之间的关联。
  • Notion 笔记 ID: K2A-F3-2
  • 创建日期: 2025-02-13
  • 更新日期: 2025-02-13
  • 许可: 欢迎转载。 请注明作者 张宇 并附上原文链接 yuzhang.io

目录


1. 文件结构总览

假设我们要创建一个简单的个人网站。以下是一个典型的简单 Next.js 项目结构:

my-nextjs-site/
├── app/                        # App Router directory (pages & layouts)
│   ├── layout.tsx              # Root layout (wraps all pages)
│   ├── page.tsx                # Home page (/)
│   ├── globals.css             # Global styles
│   ├── about/
│   │   └── page.tsx            # About page (/about)
│   ├── blog/
│   │   ├── page.tsx            # Blog index (/blog)
│   │   └── [slug]/
│   │       └── page.tsx        # Individual blog post (/blog/post-name)
│   └── favicon.ico             # Site favicon
├── components/                 # Reusable UI components
│   ├── Nav.tsx
│   └── Footer.tsx
├── content/                    # Markdown content files
│   ├── blog/
│   └── notes/
├── lib/                        # Utility functions & helpers
│   └── markdown.ts
├── public/                     # Static assets (images, fonts, etc.)
│   └── images/
├── package.json                # Node.js dependencies & scripts
├── tsconfig.json               # TypeScript configuration
├── next.config.ts              # Next.js configuration
├── postcss.config.mjs          # PostCSS configuration (for Tailwind)
├── eslint.config.mjs           # ESLint configuration
└── .gitignore                  # Git ignore rules

2. 基础设施与配置文件

这些文件配置了整个工具链。


2.1 package.json

是什么: Node.js 项目的清单文件。它声明了项目名称、可运行的脚本命令、以及项目所需的所有依赖(库)。

为什么需要: 如果没有 package.jsonnpm install / pnpm install 就不知道该下载什么,编译脚本也不会存在。这是每个 Node.js 项目都必需的文件。

示例:

{
  "name": "my-nextjs-site",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "eslint"
  },
  "dependencies": {
    "gray-matter": "^4.0.3",
    "next": "16.1.6",
    "react": "19.2.3",
    "react-dom": "19.2.3",
    "rehype-highlight": "^7.0.2",
    "remark": "^15.0.1",
    "remark-gfm": "^4.0.1",
    "remark-html": "^16.0.1"
  },
  "devDependencies": {
    "@tailwindcss/postcss": "^4",
    "@types/node": "^20",
    "@types/react": "^19",
    "@types/react-dom": "^19",
    "eslint": "^9",
    "eslint-config-next": "16.1.6",
    "tailwindcss": "^4",
    "typescript": "^5"
  }
}

核心概念:

  • Scripts(脚本)npm run <脚本名>pnpm <脚本名> 运行的命令:
    • dev – 启动带热重载的开发服务器
    • build – 编译生产版本(部署时运行的命令)
    • start – 在本地启动生产版本
    • lint – 运行 ESLint 检查代码质量
  • Dependencies(运行时的依赖),包含在最终应用中:
    • nextreactreact-dom – 核心框架
    • gray-matter – 解析 markdown 文件中的 YAML frontmatter
    • remark / remark-gfm / remark-html – Markdown 处理相关
    • rehype-highlight – 代码块语法高亮
  • DevDependencies(开发依赖),仅在开发和构建时使用:
    • tailwindcss@tailwindcss/postcss – Tailwind CSS 框架
    • @types/* – TypeScript 类型定义
    • eslinteslint-config-next – 代码检查
  • 版本号前缀:
    • ^4.0.3 – "兼容 4.0.3"(允许小版本和补丁更新,但不允许大版本更新)
    • 16.1.6 – "精确到这个版本"

关联: 所有其他文件都依赖于这里列出的包。npm install / pnpm install 会读取这个文件,并且将所有依赖下载到 node_modules/ 中。


2.2 tsconfig.json

是什么: TypeScript 编译器的配置。告诉 TypeScript 如何检查和编译 .ts.tsx 文件。

为什么需要: 没有这个文件,TypeScript 会使用默认设置,而这些默认设置无法与 Next.js 配合工作(比如会有错误的模块系统、不支持 JSX、没有路径别名等)。

示例:

{
  "compilerOptions": {
    "target": "ES2017",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "strict": true,
    "noEmit": true,
    "esModuleInterop": true,
    "module": "esnext",
    "moduleResolution": "bundler",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "jsx": "react-jsx",
    "incremental": true,
    "plugins": [{"name": "next"}],
    "paths": {
      "@/*": ["./*"]
    }
  },
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
  "exclude": ["node_modules"]
}

关键设置说明:

  • target: "ES2017" – 设置为 ES2017 JavaScript(支持 async/await 等)
  • lib: ["dom", "dom.iterable", "esnext"] – 包含浏览器 API 类型(documentwindow)和现代 JavaScript 特性
  • strict: true – 启用所有严格类型检查选项(能捕获更多 bug)
  • noEmit: true – TypeScript 只检查类型,不输出 .js 文件(Next.js 使用自己的编译器 SWC)
  • jsx: "react-jsx" – 使用现代 JSX 转换(每个文件不再需要 import React
  • paths: {"@/*": ["./*"]}路径别名,让我们可以写 import Nav from "@/components/Nav" 而不是 import Nav from "../../components/Nav"@/ 前缀映射到项目根目录。

核心概念:

  • TypeScript 只检查类型,不运行代码。实际的 JavaScript 编译由 Next.js 的 SWC 编译器完成。
  • @/* 路径别名是项目约定(不是 TypeScript 标准)。必须先在这里配置好,之后Next.js 会自动读取这个文件的。

关联: 每个 .ts.tsx 文件都受此配置管辖。@/* 路径别名在整个项目中使用,避免了相对路径问题(../../../)。


2.3 next.config.ts

是什么: Next.js 框架配置。在这里自定义 Next.js 的行为(重定向、URL 重写、图片优化、实验性功能等)。

为什么需要: Next.js 启动时会查找此文件。即使内容为空,它也是未来配置的指定位置。

示例:

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  /* config options here */
  // Example options:
  // images: { domains: ['example.com'] },
  // redirects: async () => [{ source: '/old', destination: '/new', permanent: true }],
};

export default nextConfig;

核心概念:

  • .ts 扩展名意味着这个配置文件是 TypeScript(Next.js 16 原生支持)
  • 常见配置:图片优化域名、URL 重定向、自定义请求头、环境变量、实验性功能

关联: Next.js 启动时读取。影响每个页面和 API 路由。


2.4 postcss.config.mjs

是什么: PostCSS 的配置文件,PostCSS 是一个 CSS 处理工具。在大多数 Next.js 项目中,它唯一的任务就是接入 Tailwind CSS。

为什么需要: Tailwind CSS v4 作为 PostCSS 插件工作。PostCSS 在构建过程中运行,读取 CSS 文件并进行转换(将 Tailwind 工具类展开为真正的 CSS)。

示例:

const config = {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

export default config;

核心概念:

  • PostCSS 是一个用 JavaScript 插件转换 CSS 的工具(类似 CSS 版的 Babel)
  • 在 Tailwind v4 中,配置文件从 tailwind.config.js 迁移到了 CSS 中(@theme 块)
  • .mjs 扩展名表示"ES 模块 JavaScript"(允许使用 export default 语法)

关联: PostCSS 处理 app/globals.css(其中包含 @import "tailwindcss")。.tsx 文件中的每个 Tailwind 工具类都通过这个管线解析。


2.5 eslint.config.mjs

是什么: ESLint(JavaScript/TypeScript 代码检查工具)配置。可以捕获常见错误,如未使用的变量、缺失的 key 属性、无障碍访问问题等。

为什么需要: 为了确保代码质量,在上线之前发现 bug。

示例:

import { defineConfig, globalIgnores } from "eslint/config";
import nextVitals from "eslint-config-next/core-web-vitals";
import nextTs from "eslint-config-next/typescript";

const eslintConfig = defineConfig([
  ...nextVitals,    // Performance and Next.js best practices
  ...nextTs,        // TypeScript-specific rules
  globalIgnores([
    ".next/**",
    "out/**",
    "build/**",
    "next-env.d.ts",
  ]),
]);

export default eslintConfig;

核心概念:

  • ESLint 9 使用"扁平配置"格式(配置对象数组)
  • Next.js 提供预设规则集:core-web-vitals(性能)和 typescript(类型安全)
  • 代码检查中的类型检查(TypeScript)和格式检查(Prettier)是分开的

关联: 通过 npm run lint / pnpm lint 运行。它们仅是开发工具,不影响构建或运行时。


2.6 .gitignore

是什么: 熟悉 git 的人应该都知道这个 .gitignore。它告诉 Git 哪些文件和目录不纳入版本控制。

为什么需要: 防止提交生成的文件、依赖包、密钥和系统垃圾文件,避免代码库膨胀或泄露敏感信息。

被忽略的内容(分类):

  • 依赖包node_modules/(通常有数百 MB,由 npm install 重新生成)
  • 构建产物.next/out/build/(构建时生成,不是源代码)
  • 环境文件.env*(API 密钥、数据库 URL、密钥)
  • 系统文件.DS_Store(macOS)、Thumbs.db(Windows)
  • 调试日志npm-debug.log*yarn-debug.log*.pnpm-debug.log*
  • TypeScript 缓存.tsbuildinfonext-env.d.ts(自动生成)
  • 部署配置.vercel/(Vercel CLI 本地配置)

关键语法:

  • 开头的 / 表示"仅限仓库根目录"
  • 是通配符,! 用于取消之前的忽略规则

3. 全局样式

3.1 app/globals.css

是什么: 整个应用的全局样式表。导入 Tailwind CSS,定义颜色体系,并提供排版样式。

为什么需要: 每个 Web 应用都需要一个基础样式表。这个文件:

  • 激活 Tailwind CSS
  • 定义自定义颜色(亮色和暗色模式)
  • 将颜色注册为 Tailwind 工具类
  • 为渲染的 markdown 内容设置样式(.prose 类)

核心结构:

/* Import Tailwind CSS framework */
@import "tailwindcss";

/* Light mode colors */
:root {
  --background: #fafafa;
  --foreground: #171717;
  --muted: #737373;
  --border: #e5e5e5;
  --accent: #171717;
}

/* Register colors as Tailwind utilities */
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-muted: var(--muted);
  --color-border: var(--border);
  --color-accent: var(--accent);
  --font-sans: var(--font-geist-sans);
  --font-mono: var(--font-geist-mono);
}

/* Dark mode override */
@media (prefers-color-scheme: dark) {
  :root {
    --background: #0a0a0a;
    --foreground: #ededed;
    --muted: #a3a3a3;
    --border: #262626;
    --accent: #ededed;
  }
}

/* Base body styles */
body {
  background: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans), system-ui, sans-serif;
}

/* Global link reset */
a {
  color: inherit;
  text-decoration: none;
}

/* Prose styles for markdown content */
.prose h1, .prose h2, .prose h3 { ... }
.prose p { margin-bottom: 1.25em; line-height: 1.75; }
.prose code { font-family: var(--font-mono), monospace; ... }
.prose pre { background: #1e1e1e; color: #d4d4d4; ... }

核心概念:

  • CSS 自定义属性(变量):--name: value 定义,用 var(--name) 使用。它们可以级联并被覆盖(比如在暗色模式中)。
  • Tailwind v4 中的 @theme 直接在 CSS 中注册自定义主题值(取代了旧的 tailwind.config.js 方式)。这样我们就可以在 JSX 中使用 bg-backgroundtext-foregroundtext-mutedborder-border 等工具类。
  • prefers-color-scheme CSS 媒体查询,检测用户操作系统的深色/浅色模式偏好。当暗色模式激活时,CSS 变量可以自动切换。
  • .prose 模式: 一种常见约定,用于为渲染后的 HTML 内容设置样式(因为我们无法在单个元素上添加工具类)。如果将 markdown 输出包裹在 <div class="prose"> 中,标题、段落、代码块、列表都会自动获得样式。

关联:

  • app/layout.tsx 通过 import "./globals.css" 导入
  • 由 PostCSS 和 Tailwind 插件处理(在 postcss.config.mjs 中配置)
  • --font-* 变量由 layout.tsx 中的字体加载器设置

4. 根布局(Root Layout)

4.1 app/layout.tsx

是什么: 整个应用的根布局。在 Next.js App Router 中,app/layout.tsx 包裹每一个页面。它定义了 <html><body> 标签,加载字体,设置元数据,并包含出现在每个页面上的 UI 元素。

为什么需要: Next.js App Router 要求app/layout.tsx 放置一个根布局。没有根布局,Next.js 就无法渲染任何页面。这是理解 Next.js 架构最重要的一个文件。

示例:

import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import Nav from "@/components/Nav";
import Footer from "@/components/Footer";
import "./globals.css";

const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});

const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});

export const metadata: Metadata = {
  title: {
    default: "My Site",
    template: "%s — My Site",
  },
  description: "Description placeholder",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable}${geistMono.variable} antialiased`}
      >
        <div className="flex min-h-screen flex-col">
          <Nav />
          <main className="flex-1">
            <div className="mx-auto max-w-3xl px-6 py-12">
              {children}
            </div>
          </main>
          <Footer />
        </div>
      </body>
    </html>
  );
}

字体加载:

next/font 在构建时下载字体并自己托管。好处:

  • 隐私 – 不会向 Google 的服务器发送请求
  • 性能 – 不需要额外的 DNS 查询
  • 无布局偏移 – 自动优化字体加载

variable 选项创建一个 CSS 变量,而不是直接应用字体。

元数据(Metadata):

Next.js Metadata API 取代了手动编写 <title><meta> 标签:

  • title.default – 当子页面没有覆盖时使用(首页)
  • title.template – 当子页面设置 title: "About" 时,%s 被替换,生成 "About — My Site"
  • description – meta 描述标签(显示在搜索结果中)

布局结构:

  • antialiased – Tailwind 工具类,用于平滑的文本渲染
  • flex min-h-screen flex-col – Flexbox 列布局,占满整个视口高度(经典的"粘性底部"模式)
  • <main> 上的 flex-1 – 扩展以填充剩余空间(将页脚推到底部)
  • mx-auto max-w-3xl px-6 py-12 – 居中的内容列,最大宽度 768px,带内边距
  • {children} – 页面内容渲染的位置。访问 /about 时,children 变成 app/about/page.tsx 的输出

核心概念:

  • 布局不需要重建布局会在不同页面保持一致(导航时不会重新渲染)
  • 默认在服务器端运行: 默认在服务器端运行(没有 "use client" 指令)
  • children prop: Next.js 自动将匹配的页面作为 children 传入

5. 共享组件

这些是跨多个页面使用的可复用 UI 组件。可以把它们放在 components/app/ 之外),因为它们不是用于特定某个路径的。


5.1 components/Nav.tsx

是什么: 显示在每个页面顶部的导航栏。

为什么需要: 导航栏还是挺有用的(至少我个人这么觉得)

示例:

import Link from "next/link";

const navLinks = [
  { href: "/about", label: "About" },
  { href: "/blog", label: "Blog" },
  { href: "/projects", label: "Projects" },
];

export default function Nav() {
  return (
    <nav className="border-b border-border">
      <div className="mx-auto flex max-w-3xl items-center justify-between px-6 py-4">
        <Link
          href="/"
          className="font-mono text-sm font-medium tracking-tight"
        >
          My Site
        </Link>
        <div className="flex gap-6">
          {navLinks.map((link) => (
            <Link
              key={link.href}
              href={link.href}
              className="text-sm text-muted transition-colors hover:text-foreground"
            >
              {link.label}
            </Link>
          ))}
        </div>
      </div>
    </nav>
  );
}

要点:

  • 内部导航始终使用 next/link<Link>(而非 <a>):启用客户端导航(无需完整页面刷新)和自动预取
  • 数据驱动渲染: 链接对象数组 + .map()(比直接写死更简洁一些)
  • 默认在服务器端运行: 不需要交互性,然后在服务器端渲染
  • 布局对齐: max-w-3xlpx-6 与布局的内容宽度匹配
  • 悬停效果: transition-colors hover:text-foreground 创建平滑的颜色过渡

关联:app/layout.tsx 导入


5.2 components/Footer.tsx

是什么: 显示在每个页面底部的网站页脚。

示例:

export default function Footer() {
  return (
    <footer className="border-t border-border">
      <div className="mx-auto max-w-3xl px-6 py-8">
        <p className="text-sm text-muted">
          &copy; {new Date().getFullYear()} Your Name
        </p>
      </div>
    </footer>
  );
}

要点:

  • 语义化 HTML: <footer> 对屏幕阅读器和搜索引擎有意义
  • 动态年份: new Date().getFullYear() 在构建时运行(Server Component)
  • 一致的宽度: mx-auto max-w-3xl px-6 与导航栏和主内容保持一致

关联:app/layout.tsx 导入


6. 页面

在 Next.js App Router 中,app/ 内的每个 page.tsx 文件都成为一个路由。文件路径直接映射到 URL。


6.1 app/page.tsx(首页)

是什么: 首页,渲染在 /

示例:

import Link from "next/link";

const sections = [
  {
    title: "Blog",
    href: "/blog",
    description: "Some user-given description",
  },
  {
    title: "Projects",
    href: "/projects",
    description: "Some user-given description",
  },
];

export default function Home() {
  return (
    <div className="space-y-16">
      {/* Intro section */}
      <section>
        <h1 className="text-2xl font-semibold tracking-tight">Name</h1>
        <p className="mt-4 leading-7 text-muted">
          Some user-given description
        </p>
        <Link
          href="/about"
          className="mt-3 inline-block text-sm text-muted transition-colors hover:text-foreground"
        >
          More about me &rarr;
        </Link>
      </section>

      {/* Section links */}
      {sections.map((section) => (
        <section key={section.href}>
          <div className="flex items-baseline justify-between">
            <h2 className="font-mono text-xs font-medium uppercase tracking-widest text-muted">
              {section.title}
            </h2>
            <Link
              href={section.href}
              className="text-sm text-muted transition-colors hover:text-foreground"
            >
              View all &rarr;
            </Link>
          </div>
          <div className="mt-3 border-t border-border pt-4">
            <p className="text-sm text-muted">{section.description}</p>
          </div>
        </section>
      ))}
    </div>
  );
}

核心概念:

  • 基于文件的路由: 这个文件在 app/page.tsx,所以它就是首页(/
  • 没有 metadata 导出: 使用根布局中的 default 标题
  • 排版层次: 不同层级使用不同的样式
  • space-y-16 Tailwind 间距工具类,用于一致的垂直节奏(各部分之间 64px)

6.2 app/about/page.tsx

是什么: 关于页面,渲染在 /about

示例:

import type { Metadata } from "next";

export const metadata: Metadata = {
  title: "About",
};

export default function AboutPage() {
  return (
    <div className="space-y-8">
      <h1 className="text-2xl font-semibold tracking-tight">About</h1>
      <div className="space-y-4 leading-7 text-muted">
        <p>Hi, I'm Name.</p>
        <p>
          Description placeholder
        </p>
      </div>
    </div>
  );
}

核心概念:

  • 页面级元数据: 每个页面可以导出自己的 metadata 对象,与父布局的元数据合并。
  • 标题模板: 根布局定义了 title: { template: "%s — My Site" }。这个页面设置 title: "About",结果在浏览器标签中显示 "About — My Site"。

6.3 嵌套路由

Next.js 使用文件系统进行路由。动态路由和嵌套路由使用方括号和文件夹:

文件路径 URL 说明
app/blog/page.tsx /blog 博客首页
app/blog/[slug]/page.tsx /blog/post-name 单篇博客文章(动态路由)
app/blog/[...slug]/page.tsx /blog/2024/jan/post 捕获所有路由(匹配任意深度)
app/docs/[[...slug]]/page.tsx /docs/docs/a/b/c 可选捕获所有路由(包含基础路径)

动态路由示例 (app/blog/[slug]/page.tsx):

export default async function BlogPost({
  params,
}: {
  params: Promise<{ slug: string }>;
}) {
  const { slug } = await params;
  // Fetch post data using slug
  return <article>Content for {slug}</article>;
}

核心概念:

  • 文件夹名中的 [slug] 创建动态路由
  • params prop 包含路由参数
  • 在 Next.js 15+ 中,params 是一个 Promise,必须 await
  • [...slug] 捕获所有路径段(返回数组,如 ['2024', 'jan', 'post']

7. 各文件之间的关联

Next.js相关文件挺多的,刚开始我也挺一头雾水的。下面是一个各文件关系的可视化总结:

Browser requests /about
        |
        v
Next.js matches route: app/about/page.tsx
        |
        v
Next.js wraps it in: app/layout.tsx (root layout)
        |
        v
layout.tsx renders:
  <html>
    <body class="[font classes] antialiased">
      <div class="flex min-h-screen flex-col">
        <Nav />                          <-- components/Nav.tsx
        <main class="flex-1">
          <div class="mx-auto max-w-3xl px-6 py-12">
            {children}                   <-- app/about/page.tsx output
          </div>
        </main>
        <Footer />                       <-- components/Footer.tsx
      </div>
    </body>
  </html>
        |
        v
globals.css provides:                   <-- app/globals.css
  - Tailwind utilities (via @import "tailwindcss")
  - Color variables (via :root and @theme)
  - Font references (via @theme --font-sans/--font-mono)
  - Prose styles for markdown content
        |
        v
PostCSS processes the CSS              <-- postcss.config.mjs
Tailwind generates utility classes      <-- @tailwindcss/postcss plugin
TypeScript checks types                 <-- tsconfig.json
Next.js serves the result               <-- next.config.ts

元数据继承:

Root layout metadata:
  title: { default: "My Site", template: "%s — My Site" }

About page metadata:
  title: "About"

Result in browser tab: "About — My Site"

导入关系图:

app/layout.tsx
  ├── imports: next (Metadata type)
  ├── imports: next/font/google (Geist, Geist_Mono)
  ├── imports: @/components/Nav.tsx
  │     └── imports: next/link (Link)
  ├── imports: @/components/Footer.tsx
  │     └── imports: nothing
  └── imports: ./globals.css
        └── processed by: @tailwindcss/postcss (via postcss.config.mjs)

app/page.tsx
  └── imports: next/link (Link)

app/about/page.tsx
  └── imports: next (Metadata type)

8. 总结

一个典型的简单 Next.js 项目包含:

  1. 配置文件package.jsontsconfig.jsonnext.config.ts)配置工具链
  2. 全局样式app/globals.css)导入 Tailwind 并定义设计系统
  3. 根布局app/layout.tsx)用 Nav、Footer、字体和元数据包裹所有页面
  4. 共享组件components/Nav.tsxFooter.tsx)跨页面使用
  5. 页面文件app/page.tsxapp/about/page.tsx)通过文件系统定义路由

核心思维模型:

  • 文件系统就是路由app/about/page.tsx 自动变成 /about
  • 布局包裹页面并在导航间保持不变
  • 默认是 Server Components(除非你添加 "use client"
  • 路径别名@/* → 项目根目录)避免相对路径地狱
  • Metadata API 取代了手动管理 <title> 标签
  • Tailwind v4 在 CSS 中使用 @theme 而非 tailwind.config.js

这种结构对个人网站、博客和小型 Web 应用来说其实有很好的扩展性。随着项目增长,可能会添加:

  • lib/ 工具函数用于数据获取和辅助功能
  • content/ 目录用于 markdown/MDX 文件
  • 动态路由([slug])用于博客文章或文档
  • API 路由在 app/api/ 中实现后端功能

9. 参考资料

本笔记中的示例代码基于 create-next-app(Next.js 官方项目生成器)的脚手架创建的项目,然后我自己添加了导航栏、页脚、占位页面和 Tailwind CSS 设计系统。

如果想自己生成一个类似的项目,只需运行:

npx create-next-app@latest my-nextjs-site

这个工具会提示你选择 TypeScript、Tailwind CSS、App Router 啥的选项。生成的项目结构与我笔记中描述的应该非常接近。