name: vercel-deploy description: | 用于将 Next.js 应用程序部署到 Vercel 时使用。 触发场景:vercel.json 配置、构建优化、环境变量设置、 自定义域名配置、API 代理设置或部署故障排除。 不适用于:仅后端部署、非 Vercel 托管或本地开发设置。
Vercel 部署技能
以最优构建设置、环境配置和自定义域名设置,将 Next.js 应用程序专业部署到 Vercel。
快速参考
| 任务 | 文件/命令 |
|---|---|
| 配置构建 | vercel.json |
| 设置环境变量 | Vercel 仪表板或 CLI |
| 部署 | vercel --prod |
| 检查状态 | vercel inspect |
| 自定义域名 | Vercel 仪表板 > 设置 > 域名 |
项目结构
项目/
├── vercel.json # Vercel 配置
├── next.config.js # Next.js 配置
├── .env.local # 本地开发(不提交)
├── .env.example # 模板(提交)
├── docs/
│ └── deployment.md # 部署文档
└── frontend/ # Next.js 应用
├── app/
├── public/
└── src/
vercel.json 配置
基础配置
{
"buildCommand": "npm run build",
"outputDirectory": ".next",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"],
"env": {
"NEXT_PUBLIC_API_URL": "@api_url"
}
}
包含重写的高级配置
{
"version": 2,
"buildCommand": "npm run build",
"outputDirectory": ".next",
"installCommand": "npm install",
"framework": "nextjs",
"regions": ["iad1"],
"rewrites": [
{
"source": "/api/:path*",
"destination": "https://api.yourdomain.com/:path*"
}
],
"headers": [
{
"source": "/(.*)",
"headers": [
{
"key": "X-Content-Type-Options",
"value": "nosniff"
},
{
"key": "X-Frame-Options",
"value": "DENY"
},
{
"key": "X-XSS-Protection",
"value": "1; mode=block"
}
]
},
{
"source": "/static/:path*",
"headers": [
{
"key": "Cache-Control",
"value": "public, max-age=31536000, immutable"
}
]
},
{
"source": "/api/:path*",
"headers": [
{
"key": "Access-Control-Allow-Origin",
"value": "*"
}
]
}
],
"redirects": [
{
"source": "/old-path/:path*",
"destination": "/new-path/:path*",
"permanent": true
},
{
"source": "/www/:path*",
"destination": "/:path*",
"permanent": true
}
]
}
Next.js 配置集成
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
// Vercel 的输出配置
output: 'standalone',
// 图片优化
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'api.yourdomain.com',
pathname: '/uploads/**',
},
],
formats: ['image/avif', 'image/webp'],
},
// 安全头
async headers() {
return [
{
source: '/:path*',
headers: [
{
key: 'X-DNS-Prefetch-Control',
value: 'on',
},
{
key: 'Referrer-Policy',
value: 'origin-when-cross-origin',
},
],
},
];
},
// 重定向
async redirects() {
return [
{
source: '/legacy/:path*',
destination: '/:path*',
permanent: true,
},
];
},
// 实验性功能
experimental: {
serverActions: {
allowedOrigins: ['yourdomain.com'],
},
},
};
module.exports = nextConfig;
环境变量
变量命名约定
| 前缀 | 访问权限 | 描述 |
|---|---|---|
NEXT_PUBLIC_ |
客户端 + 服务器 | 暴露给浏览器 |
| 无前缀 | 仅服务器 | 仅限后端/API 使用 |
必需变量
# .env.example - 复制到 .env.local 用于本地开发
# API 配置
# 后端 API URL(开发环境)
NEXT_PUBLIC_API_URL="http://localhost:8000/api/v1"
# 身份验证
NEXT_PUBLIC_AUTH_ENABLED="true"
# 功能开关
NEXT_PUBLIC_ENABLE_DARK_MODE="true"
NEXT_PUBLIC_SHOW_BETA_FEATURES="false"
生产环境变量(在 Vercel 仪表板中设置)
# 生产环境变量
# API 配置
NEXT_PUBLIC_API_URL="https://api.yourdomain.com"
# 可选:分析
NEXT_PUBLIC_GA_ID="G-XXXXXXXXXX"
NEXT_PUBLIC_POSTHOG_KEY="phc_xxx"
# 可选:错误追踪
NEXT_PUBLIC_SENTRY_DSN="https://xxx@sentry.io/xxx"
敏感变量(仅服务器)
这些变量不应有 NEXT_PUBLIC_ 前缀:
# 仅服务器(绝不暴露给客户端)
API_SECRET_KEY="vercel-secret-key"
DATABASE_URL="postgresql://..."
REDIS_URL="redis://..."
Vercel CLI 部署
安装和登录
# 安装 Vercel CLI
npm i -g vercel
# 登录 Vercel
vercel login
# 链接到项目
cd frontend
vercel link
部署命令
# 部署到预览(暂存)环境
vercel
# 部署到生产环境
vercel --prod
# 带环境变量部署
vercel --env=NODE_ENV=production
# 从 Vercel 拉取环境变量
vercel env pull .env.local
CI/CD 部署
# 在 CI 流水线中
npm i -g vercel
vercel --token=$VERCEL_TOKEN --yes
自定义域名设置
在 Vercel 中添加域名
- 前往 Vercel 仪表板 > 项目 > 设置 > 域名
- 添加您的域名(例如
yourdomain.com) - 配置 DNS 记录
DNS 配置
# 根域名(yourdomain.com)
类型: A
名称: @
值: 76.76.21.21
# www 子域名
类型: CNAME
名称: www
值: cname.vercel-dns.com.
# API 子域名(可选)
类型: CNAME
名称: api
值: cname.vercel-dns.com.
www 到根域名重定向
{
"redirects": [
{
"source": "/:path*",
"destination": "https://yourdomain.com/:path*",
"permanent": true
}
]
}
API 代理设置
选项 1:Vercel 重写(推荐)
{
"rewrites": [
{
"source": "/api/:path*",
"destination": "https://api.yourdomain.com/:path*"
}
]
}
选项 2:Next.js 重写
// next.config.js
async rewrites() {
return [
{
source: '/api/:path*',
destination: `${process.env.NEXT_PUBLIC_API_URL}/:path*`,
},
];
}
API 边缘函数(高级)
// frontend/app/api/[...route]/route.ts
import { NextRequest, NextResponse } from 'next/server';
export async function GET(request: NextRequest) {
const response = await fetch(
`${process.env.NEXT_PUBLIC_API_URL}/api/v1/endpoint`,
{
headers: {
'Authorization': request.headers.get('Authorization') || '',
'Content-Type': 'application/json',
},
}
);
const data = await response.json();
return NextResponse.json(data);
}
构建优化
构建命令
# 标准构建
npm run build
# 仅进行 TypeScript 检查
npm run build -- --no-lint
# 自定义构建
next build
性能设置
// next.config.js
const nextConfig = {
// 启用 SWC 压缩器(构建更快)
swcMinify: true,
// 编译器选项
compiler: {
removeConsole: process.env.NODE_ENV === 'production',
},
// 图片优化
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
// 启用 React 严格模式
reactStrictMode: true,
// 生成 Etag
generateEtags: true,
};
包分析
# 安装包分析器
npm install -D @next/bundle-analyzer
# next.config.js
const withBundleAnalyzer = require('@next/bundle-analyzer')({
enabled: process.env.ANALYZE === 'true',
});
module.exports = withBundleAnalyzer({
// 您的配置
});
错误页面
自定义 404 页面
// frontend/app/not-found.tsx
import Link from 'next/link';
export default function NotFound() {
return (
<div className="min-h-screen flex flex-col items-center justify-center">
<h1 className="text-4xl font-bold">404 - 页面未找到</h1>
<p className="mt-2 text-gray-600">
您查找的页面不存在。
</p>
<Link
href="/"
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded"
>
返回首页
</Link>
</div>
);
}
自定义 500 页面
// frontend/app/error.tsx
'use client';
export default function Error({
error,
reset,
}: {
error: Error & { digest?: string };
reset: () => void;
}) {
return (
<div className="min-h-screen flex flex-col items-center justify-center">
<h1 className="text-4xl font-bold">出错了!</h1>
<p className="mt-2 text-gray-600">
发生了一个意外错误。
</p>
<button
onClick={() => reset()}
className="mt-4 px-4 py-2 bg-blue-600 text-white rounded"
>
重试
</button>
</div>
);
}
全局错误边界
// frontend/app/global-error.tsx
'use client';
export default function GlobalError({
error,
}: {
error: Error & { digest?: string };
}) {
return (
<html>
<body>
<div className="min-h-screen flex items-center justify-center">
<h1 className="text-2xl">应用程序错误</h1>
</div>
</body>
</html>
);
}
部署清单
- [ ] 本地构建成功:
npm run build无错误完成 - [ ] Vercel 构建成功:部署预览构建正确
- [ ] 正确的 API URL:NEXT_PUBLIC_API_URL 指向正确的环境
- [ ] 无敏感变量暴露:密钥没有
NEXT_PUBLIC_前缀 - [ ] 配置了 404 页面:存在自定义 not-found.tsx
- [ ] 配置了 500 页面:存在自定义 error.tsx
- [ ] 设置了自定义域名:DNS 记录配置正确
- [ ] 强制 HTTPS:自动 SSL 证书
- [ ] 配置了重定向:www 到根域名或反之
- [ ] 设置了缓存头:静态资源正确缓存
部署文档模板
# 部署指南
## 快速部署
[](https://vercel.com/new)
## 环境变量
### 开发环境
```bash
NEXT_PUBLIC_API_URL=http://localhost:8000/api/v1
生产环境
NEXT_PUBLIC_API_URL=https://api.yourdomain.com
自定义域名
- 在 Vercel 仪表板 > 设置 > 域名 中添加
yourdomain.com - 配置 DNS:
- A 记录:
@->76.76.21.21 - CNAME:
www->cname.vercel-dns.com
- A 记录:
故障排除
构建失败
# 本地运行查看错误
npm run build
环境变量不生效
- 检查变量名是否以
NEXT_PUBLIC_开头以允许客户端访问 - 添加新变量后重新部署
生产环境 404
- 验证
vercel.json中的 outputDirectory 与构建输出匹配 - 检查页面文件是否在
app/目录中(App Router)
## 集成点
| 技能 | 集成 |
|-------|-------------|
| `@frontend-nextjs-app-router` | Next.js App Router 配置 |
| `@env-config` | 环境变量管理 |
| `@tailwind-css` | CSS 构建优化 |
| `@api-route-design` | API 路由和重写 |
| `@error-handling` | 自定义错误页面 |