开发环境搭建与工程脚手架

工欲善其事,必先利其器。本章从零开始,搭建一个生产级的 Next.js 16 开发环境——从 Node.js 版本管理、create-next-app 脚手架、pnpm 包管理、ESLint + Prettier 代码规范,到环境变量的类型安全管理,每一步都给出最佳实践和踩坑提示。

1. 基础环境准备

1.1 Node.js 版本管理

Next.js 16 要求 Node.js 18.18+,推荐使用 Node.js 20 LTS 或 22 LTS。使用 fnm(Fast Node Manager)管理多版本:

# macOS / Linux 安装 fnm
curl -fsSL https://fnm.vercel.app/install | bash
 
# Windows(通过 winget)
winget install Schniz.fnm
 
# 安装并使用 Node.js 20 LTS
fnm install 20
fnm use 20
fnm default 20
 
# 验证
node -v  # v20.x.x
npm -v   # 10.x.x

在项目根目录创建 .node-version 文件,确保团队成员使用相同版本:

echo "20" > .node-version

1.2 包管理器:pnpm

Next.js 16 支持 npm、yarn、pnpm。推荐 pnpm——速度快、磁盘空间节省、严格的依赖管理:

# 通过 corepack 启用(Node.js 内置)
corepack enable
corepack prepare pnpm@latest --activate
 
# 验证
pnpm -v  # 9.x.x

package.json 中锁定包管理器:

{
  "packageManager": "[email protected]",
  "engines": {
    "node": ">=20.0.0"
  }
}

1.3 编辑器配置

VS Code / Cursor 推荐扩展

// .vscode/extensions.json
{
  "recommendations": [
    "dbaeumer.vscode-eslint",
    "esbenp.prettier-vscode",
    "bradlc.vscode-tailwindcss",
    "prisma.prisma",
    "ms-vscode.vscode-typescript-next",
    "formulahendry.auto-rename-tag"
  ]
}

编辑器通用配置

// .vscode/settings.json
{
  "editor.defaultFormatter": "esbenp.prettier-vscode",
  "editor.formatOnSave": true,
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": "explicit"
  },
  "typescript.tsdk": "node_modules/typescript/lib",
  "tailwindCSS.experimental.classRegex": [
    ["cva\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"],
    ["cn\\(([^)]*)\\)", "[\"'`]([^\"'`]*).*?[\"'`]"]
  ]
}

2. 使用 create-next-app 创建项目

2.1 一键创建

pnpm create next-app@latest ai-saas-platform
 
# 交互式选项(推荐选择)
 Would you like to use TypeScript? Yes
 Would you like to use ESLint? Yes
 Would you like to use Tailwind CSS? Yes
 Would you like your code inside a `src/` directory? No
 Would you like to use App Router? Yes
 Would you like to use Turbopack for next dev? Yes (Next.js 16 默认)
 Would you like to customize the import alias? Yes @/*
关于 src/ 目录

选择 No。在 Next.js App Router 中,app/ 目录已经是很好的组织边界。加 src/ 多一层嵌套,收益不大,反而增加路径深度。如果团队有强烈偏好,选 Yes 也没问题——只是路径变成 src/app/

2.2 生成的目录结构

ai-saas-platform/
├── app/
│   ├── favicon.ico
│   ├── globals.css
│   ├── layout.tsx          # 根布局
│   └── page.tsx            # 首页
├── public/
│   ├── file.svg
│   ├── globe.svg
│   └── ...
├── .eslintrc.json          # ESLint 配置
├── .gitignore
├── next-env.d.ts           # Next.js 类型声明
├── next.config.ts          # Next.js 配置
├── package.json
├── pnpm-lock.yaml
├── postcss.config.mjs      # PostCSS(Tailwind)
├── tailwind.config.ts      # Tailwind 配置
└── tsconfig.json           # TypeScript 配置

2.3 验证项目启动

cd ai-saas-platform
pnpm dev
 
# 输出
 Next.js 16.x.x
  - Local:    http://localhost:3000
  - Network:  http://192.168.x.x:3000
  - Turbopack: enabled
 
 Starting...
 Ready in 1.2s

访问 http://localhost:3000,看到 Next.js 默认欢迎页即成功。

3. 项目结构规划

3.1 AI SaaS 项目推荐目录结构

脚手架生成的结构太简单,我们需要扩展为生产级结构:

ai-saas-platform/
├── app/                        # 路由与页面
│   ├── (auth)/                 # 认证相关路由组
│   │   ├── login/page.tsx
│   │   ├── register/page.tsx
│   │   └── layout.tsx
│   ├── (dashboard)/            # 仪表盘路由组
│   │   ├── chat/
│   │   ├── knowledge/
│   │   ├── settings/
│   │   └── layout.tsx
│   ├── (marketing)/            # 营销页路由组
│   │   ├── page.tsx            # 首页
│   │   ├── pricing/page.tsx
│   │   └── layout.tsx
│   ├── admin/                  # 管理后台
│   ├── api/                    # API Routes
│   │   ├── chat/route.ts
│   │   ├── webhook/
│   │   └── trpc/[trpc]/route.ts
│   ├── layout.tsx              # 根布局
│   ├── not-found.tsx           # 404
│   └── globals.css
├── components/                 # 共享组件
│   ├── ui/                     # shadcn/ui 组件
│   ├── chat/                   # 业务组件:聊天
│   ├── knowledge/              # 业务组件:知识库
│   └── layout/                 # 布局组件
├── lib/                        # 工具库
│   ├── db/                     # 数据库
│   │   ├── schema.ts           # Drizzle/Prisma Schema
│   │   ├── client.ts           # 数据库客户端
│   │   └── migrations/
│   ├── ai/                     # AI 相关
│   │   ├── models.ts           # 模型配置
│   │   └── tools.ts            # Agent 工具
│   ├── auth/                   # 认证
│   │   └── config.ts           # Auth.js 配置
│   ├── stripe/                 # 支付
│   │   └── config.ts
│   ├── email/                  # 邮件
│   │   └── templates/
│   ├── utils.ts                # 通用工具函数
│   └── constants.ts            # 常量
├── hooks/                      # 自定义 React Hooks
├── types/                      # 全局类型定义
├── config/                     # 应用配置
│   └── site.ts                 # 站点元数据
├── public/                     # 静态资源
├── .env.local                  # 本地环境变量
├── .env.example                # 环境变量模板
├── next.config.ts
├── tailwind.config.ts
├── tsconfig.json
└── package.json

3.2 路由分组策略

Next.js 的 Route Groups(圆括号目录)是组织大型应用的关键——它们影响布局但不影响 URL

app/
├── (marketing)/          # 营销页 — 公开布局(Header + Footer)
│   ├── layout.tsx        # 公开布局
│   ├── page.tsx          # / (首页)
│   ├── pricing/page.tsx  # /pricing
│   └── blog/page.tsx     # /blog
├── (auth)/               # 认证页 — 居中卡片布局
│   ├── layout.tsx        # 认证布局
│   ├── login/page.tsx    # /login
│   └── register/page.tsx # /register
├── (dashboard)/          # 仪表盘 — 侧边栏布局(需登录)
│   ├── layout.tsx        # 仪表盘布局(含侧边栏)
│   ├── chat/page.tsx     # /chat
│   └── settings/page.tsx # /settings
└── admin/                # 管理后台 — 独立布局(需管理员权限)
    ├── layout.tsx
    └── page.tsx          # /admin

4. ESLint + Prettier 代码规范

4.1 ESLint Flat Config

Next.js 16 推荐使用 ESLint 9 的 Flat Config 格式:

# 安装依赖
pnpm add -D eslint @eslint/js typescript-eslint eslint-plugin-react eslint-plugin-react-hooks eslint-config-next
// eslint.config.mjs
import { dirname } from 'path'
import { fileURLToPath } from 'url'
import { FlatCompat } from '@eslint/eslintrc'
import js from '@eslint/js'
 
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
 
const compat = new FlatCompat({
  baseDirectory: __dirname,
})
 
export default [
  js.configs.recommended,
  ...compat.extends('next/core-web-vitals', 'next/typescript'),
  {
    rules: {
      '@typescript-eslint/no-unused-vars': ['warn', {
        argsIgnorePattern: '^_',
        varsIgnorePattern: '^_',
      }],
      'react/no-unescaped-entities': 'off',
      '@next/next/no-img-element': 'off',
    },
  },
]

4.2 Prettier 配置

pnpm add -D prettier prettier-plugin-tailwindcss
// .prettierrc
{
  "semi": false,
  "singleQuote": true,
  "trailingComma": "all",
  "printWidth": 100,
  "tabWidth": 2,
  "plugins": ["prettier-plugin-tailwindcss"]
}

prettier-plugin-tailwindcss 会自动排序 Tailwind 类名,保持团队一致性。

// .prettierignore
node_modules
.next
pnpm-lock.yaml

4.3 Git Hooks:Husky + lint-staged

确保每次提交都通过代码检查:

pnpm add -D husky lint-staged
pnpm exec husky init
// package.json 中添加
{
  "lint-staged": {
    "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md,css}": ["prettier --write"]
  }
}
# .husky/pre-commit
pnpm exec lint-staged

5. 环境变量管理

5.1 Next.js 环境变量规则

Next.js 有一套明确的环境变量加载规则:

文件加载时机Git 跟踪
.env所有环境✅ 是
.env.local所有环境(覆盖 .env)❌ 否
.env.developmentnext dev✅ 是
.env.productionnext build / next start✅ 是

关键规则:只有以 NEXT_PUBLIC_ 前缀的变量才会暴露给客户端浏览器。

# .env.local
# 🔒 服务端专用(不会暴露给浏览器)
DATABASE_URL="postgresql://user:pass@localhost:5432/ai_saas"
OPENAI_API_KEY="sk-..."
STRIPE_SECRET_KEY="sk_test_..."
AUTH_SECRET="your-auth-secret"
 
# 🌐 客户端可用(会暴露给浏览器)
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_POSTHOG_KEY="phc_..."

5.2 类型安全的环境变量

裸用 process.env.XXX 没有类型提示,也无法在构建时校验。使用 @t3-oss/env-nextjs 实现类型安全:

pnpm add @t3-oss/env-nextjs zod
// lib/env.ts
import { createEnv } from '@t3-oss/env-nextjs'
import { z } from 'zod'
 
export const env = createEnv({
  server: {
    DATABASE_URL: z.string().url(),
    OPENAI_API_KEY: z.string().startsWith('sk-'),
    STRIPE_SECRET_KEY: z.string().startsWith('sk_'),
    AUTH_SECRET: z.string().min(32),
    RESEND_API_KEY: z.string(),
    NODE_ENV: z.enum(['development', 'production', 'test']).default('development'),
  },
  client: {
    NEXT_PUBLIC_APP_URL: z.string().url(),
    NEXT_PUBLIC_POSTHOG_KEY: z.string().optional(),
  },
  runtimeEnv: {
    DATABASE_URL: process.env.DATABASE_URL,
    OPENAI_API_KEY: process.env.OPENAI_API_KEY,
    STRIPE_SECRET_KEY: process.env.STRIPE_SECRET_KEY,
    AUTH_SECRET: process.env.AUTH_SECRET,
    RESEND_API_KEY: process.env.RESEND_API_KEY,
    NODE_ENV: process.env.NODE_ENV,
    NEXT_PUBLIC_APP_URL: process.env.NEXT_PUBLIC_APP_URL,
    NEXT_PUBLIC_POSTHOG_KEY: process.env.NEXT_PUBLIC_POSTHOG_KEY,
  },
})

使用时获得完整类型提示:

import { env } from '@/lib/env'
 
// ✅ 类型安全
env.DATABASE_URL     // string(保证是有效 URL)
env.OPENAI_API_KEY   // string(保证以 sk- 开头)
 
// ❌ 编译报错:client 环境变量不能在服务端反过来用
// env.NEXT_PUBLIC_APP_URL  // 在客户端组件中可用

如果缺少必需的环境变量,应用在构建时就会报错,而不是运行时才发现。

5.3 环境变量模板

# .env.example(提交到 Git,作为团队参考)
# Database
DATABASE_URL="postgresql://user:pass@localhost:5432/ai_saas"
 
# Auth
AUTH_SECRET="generate-with-openssl-rand-base64-32"
 
# AI
OPENAI_API_KEY="sk-..."
 
# Stripe
STRIPE_SECRET_KEY="sk_test_..."
STRIPE_WEBHOOK_SECRET="whsec_..."
 
# Email
RESEND_API_KEY="re_..."
 
# Public
NEXT_PUBLIC_APP_URL="http://localhost:3000"
NEXT_PUBLIC_POSTHOG_KEY=""

6. next.config.ts 基础配置

// next.config.ts
import type { NextConfig } from 'next'
 
const nextConfig: NextConfig = {
  // React Compiler(实验性,推荐开启)
  experimental: {
    reactCompiler: true,
  },
 
  // 图片域名白名单
  images: {
    remotePatterns: [
      { hostname: 'avatars.githubusercontent.com' },
      { hostname: '*.amazonaws.com' },
      { hostname: '*.cloudflare.com' },
    ],
  },
 
  // 独立部署模式(Docker 部署需要)
  output: 'standalone',
 
  // 重定向
  async redirects() {
    return [
      {
        source: '/app',
        destination: '/chat',
        permanent: true,
      },
    ]
  },
}
 
export default nextConfig

7. 第一次提交

# 初始化 Git
git init
git add .
git commit -m "feat: initial Next.js 16 project setup
 
- Next.js 16 with App Router and Turbopack
- TypeScript strict mode
- Tailwind CSS v4 + PostCSS
- ESLint Flat Config + Prettier
- Husky + lint-staged
- Type-safe environment variables (@t3-oss/env-nextjs)
- Production-ready directory structure"

本章小结

  • 基础环境:Node.js 20+ (fnm 管理) + pnpm 9+ (corepack 启用) + VS Code/Cursor 配置
  • create-next-app:使用 App Router + TypeScript + Tailwind CSS + Turbopack 创建项目
  • 目录结构:按 Route Groups 组织(marketing/auth/dashboard/admin),按功能组织 lib 目录
  • 代码规范:ESLint Flat Config + Prettier + Tailwind 类名排序 + Husky pre-commit
  • 环境变量@t3-oss/env-nextjs + Zod 实现构建时校验、运行时类型安全
  • next.config.ts:React Compiler、图片白名单、standalone 输出

下一章,我们将深入 App Router 的目录结构,理解每一个特殊文件的作用和最佳实践。