Nuxt.js(Vue 生态的全栈框架)在 Vercel 上有着极佳的支持:通过内置的 Nitro Server 引擎,Nuxt 项目可以完美适配 Vercel Functions 的运行时,实现 SSR(服务端渲染)、SSG(静态生成)、API Routes、Server Middleware 等所有能力。本文从初始化项目到生产部署,逐个讲解 Nuxt 在 Vercel 上的最佳实践。
一、项目初始化与模式选择
1.1 创建 Nuxt 项目
# 创建项目
npx nuxi@latest init my-nuxt-app
# 进入目录并安装依赖
cd my-nuxt-app
npm install
# 安装 Vercel 适配器(必须)
npm install -D @nuxtjs/vercel-builder
# 实际 Nuxt Nitro 自带 vercel 预设,通常不需要额外安装
Nuxt 3 的 Nitro 引擎自带多种 preset,其中 vercel 是专门为 Vercel Functions 优化过的。
1.2 SSR vs SSG vs ISR:怎么选?
Nuxt 的渲染模式由 nuxt.config.ts 中的 ssr 和 routeRules 决定:
| 模式 | 配置 | 适用场景 | Vercel 适配 |
|---|---|---|---|
| SSR | ssr: true(默认) | 需要服务端数据的动态页、登录态页面 | ✅ Nitro → Vercel Serverless Functions |
| SSG | ssr: true + routeRules: { '/**': { isr: false, prerender: true } } | 静态站、博客、文档 | ✅ 静态文件直接上传到 Vercel CDN |
| ISR | routeRules: { '/**': { isr: 60 } } | 大部分内容不常变但需及时更新 | ✅ 混合:静态 CDN + Serverless stale-while-revalidate |
| SPA | ssr: false | 纯后台管理、强客户端交互应用 | ✅ 仅 HTML + JS 文件 |
建议决策:
- 内容站/博客:SSG(最快、最省 Serverless 调用)
- SaaS 前台:ISR(兼顾速度和数据新鲜度)
- 后台管理系统:SSR 或 SPA
1.3 nuxt.config.ts 核心配置
// nuxt.config.ts
export default defineNuxtConfig({
// 默认开启 SSR
ssr: true,
// 静态资源/缓存策略
routeRules: {
// 首页 SSR(动态内容)
'/': { isr: 60 },
// 博客列表页:ISR 5 分钟刷新一次
'/blog/**': { isr: 300 },
// 博客详情页:静态生成 + 按需重新验证
'/blog/**': { prerender: true, isr: 3600 },
// 关于页:纯静态,永不重新验证
'/about': { prerender: true },
// API 路由:不走缓存
'/api/**': { cors: true, isr: false },
},
nitro: {
// 显式指定 Vercel 预设
preset: 'vercel',
// 为 Vercel Functions 设置内存和超时
vercel: {
functions: {
maxDuration: 10, // 函数最大执行时间(秒)
},
},
},
// 开发服务器代理(本地开发用)
devtools: { enabled: true },
compatibilityDate: '2025-01-01',
});
*preset: 'vercel'* 是核心配置,它告诉 Nitro 将服务端代码打包为 Vercel Functions 兼容的格式。
二、API Routes 与 Server 引擎
Nuxt 3 的 Server 引擎基于 Nitro,API 路由放在 server/api/ 和 server/routes/ 下,Vercel 会自动将其转换为 Serverless Functions。
2.1 基础 API 路由
// server/api/hello.get.ts
export default defineEventHandler((event) => {
return {
message: 'Hello from Nuxt on Vercel!',
timestamp: new Date().toISOString(),
};
});
文件命名约定:
.get.ts→ 只响应 GET 请求.post.ts→ 只响应 POST 请求.ts→ 响应所有 HTTP 方法(需手动判断event.method)
2.2 带参数的 API
// server/api/users/[id].get.ts
export default defineEventHandler(async (event) => {
const id = getRouterParam(event, 'id');
// 这里可以查询数据库
// const user = await db.findUserById(id);
return {
id,
name: `User ${id}`,
};
});
2.3 与数据库交互
以 Prisma + Postgres 为例:
// server/utils/prisma.ts
import { PrismaClient } from '@prisma/client';
const globalForPrisma = globalThis as { prisma?: PrismaClient };
export const prisma = globalForPrisma.prisma ?? new PrismaClient();
if (process.env.NODE_ENV !== 'production') globalForPrisma.prisma = prisma;
// server/api/posts/index.get.ts
import { prisma } from '~/server/utils/prisma';
export default defineEventHandler(async () => {
const posts = await prisma.post.findMany({
orderBy: { createdAt: 'desc' },
take: 20,
});
return posts;
});
⚠️ 注意:Nuxt Server 路由在 Vercel 上运行在 Node.js Serverless Functions 中(不是 Edge Runtime)。Prisma 等依赖 Node.js 绑定的库可以正常工作。如果你想把部分逻辑放到 Edge,需要手动编写 Vercel Edge Middleware(与 Nuxt Server 路由是两套体系)。
2.4 获取请求体和查询参数
// server/api/upload.post.ts
export default defineEventHandler(async (event) => {
// 查询参数:?category=tech
const query = getQuery(event);
const category = query.category as string;
// 请求体(JSON)
const body = await readBody(event);
// 表单数据
const formData = await readMultipartFormData(event);
return { category, body };
});
三、部署前的准备
3.1 环境变量配置
创建 .env:
NUXT_DATABASE_URL="postgresql://user:pass@host:5432/db"
NUXT_API_SECRET="your-secret-key"
NUXT_PUBLIC_APP_NAME="My Nuxt App"
Nuxt 的环境变量分为两类:
| 前缀 | 作用域 | 示例 |
|---|---|---|
NUXT_ 或 NUXT_PRIVATE_ | 服务端专用 | 数据库连接、API Secret |
NUXT_PUBLIC_ | 服务端 + 客户端共享 | App 名称、API Base URL |
在代码中读取:
// 服务端(Server Route、SSR 组件)
const config = useRuntimeConfig();
console.log(config.databaseUrl); // 服务端私有
console.log(config.public.appName); // 客户端也可访问
<!-- 客户端组件 -->
<template>
<h1>{{ appName }}</h1>
</template>
<script setup>
const appName = useRuntimeConfig().public.appName;
</script>
3.2 Vercel 环境变量设置
- Vercel Dashboard → 项目 → Settings → Environment Variables
- 添加所有
NUXT_和NUXT_PUBLIC_开头的变量 - Production 和 Preview 环境都配置一遍(或至少 Production)
3.3 构建配置检查
Vercel 会自动识别 Nuxt 项目,但建议确认构建配置:
- Build Command:
npm run build(或nuxt build) - Output Directory:
.output/public - Install Command:
npm install
如果 nuxt.config.ts 中正确设置了 preset: 'vercel',Vercel 会自动生成 .vercel/output/functions/ 下的 Functions 打包文件。
四、在 Vercel 上部署
4.1 Git 推送自动部署
git init
git add .
git commit -m "Init Nuxt project"
git remote add origin https://github.com/yourname/my-nuxt-app.git
git push -u origin main
- 在 Vercel Dashboard 点击 “New Project”
- 导入 GitHub 仓库
my-nuxt-app - Vercel 自动识别为 Nuxt 项目,保持默认构建配置
- 确认 Environment Variables 已添加
- 点击 “Deploy”,等待构建完成
4.2 手动部署(Vercel CLI)
# 安装 Vercel CLI
npm i -g vercel
# 登录
vercel login
# 在项目根目录执行
vercel
# 首次会提示配置,后续推送自动部署
# 部署到生产环境
vercel --prod
4.3 验证部署
构建完成后,访问 https://my-nuxt-app.vercel.app 验证:
# 测试首页
curl https://my-nuxt-app.vercel.app
# 测试 API
curl https://my-nuxt-app.vercel.app/api/hello
# 测试带参数 API
curl https://my-nuxt-app.vercel.app/api/users/123
五、图片与静态资源优化
5.1 Nuxt Image 模块
npm install -D @nuxt/image
// nuxt.config.ts
export default defineNuxtConfig({
modules: ['@nuxt/image'],
image: {
domains: ['cdn.yourdomain.com'],
screens: {
xs: 320,
sm: 640,
md: 768,
lg: 1024,
xl: 1280,
},
},
});
<!-- 自动响应式图片 -->
<NuxtImg
src="/hero.jpg"
alt="Hero"
sizes="xs:100vw sm:50vw md:400px"
loading="lazy"
placeholder
/>
@nuxt/image 在 Vercel 上会自动使用 Vercel Image Optimization API,无需配置第三方图片 CDN。
5.2 静态资源缓存
Nuxt 的 .output/public/ 目录下的文件会被 Vercel 自动上传到 CDN。为了进一步优化缓存:
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
routeRules: {
'/_nuxt/**': {
headers: {
'cache-control': 'public, max-age=31536000, immutable',
},
},
'/images/**': {
headers: {
'cache-control': 'public, max-age=604800',
},
},
},
},
});
六、ISR 与缓存策略
6.1 ISR 配置详解
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 首页:ISR 60 秒
'/': { isr: 60 },
// 内容页:ISR 1 小时
'/posts/**': { isr: 3600 },
// 用户页:SSR(不缓存)
'/user/**': { isr: false },
// API:CORS + 不缓存
'/api/**': { isr: false, cors: true },
},
});
ISR 在 Vercel 上的行为:
- 首次请求:Serverless Function 渲染,返回 HTML,同时缓存到 Vercel CDN
- 缓存期内(如 60 秒):后续请求直接命中 CDN,Vercel 不计费 Serverless 执行
- 缓存过期后:下一个请求会触发背景重新生成(stale-while-revalidate),用户仍收到旧缓存
6.2 On-Demand Revalidation(手动失效)
// server/api/revalidate.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const { path, token } = body;
// 校验密钥
const config = useRuntimeConfig();
if (token !== config.revalidateToken) {
throw createError({ statusCode: 401, statusMessage: 'Invalid token' });
}
// 触发重新验证
const nitro = useNitroApp();
await nitio.hooks.callHook(' nitro:cache:invalidate', { path });
return { revalidated: true };
});
从 CMS 或后台管理触发失效:
curl -X POST https://my-nuxt-app.vercel.app/api/revalidate \
-H "Content-Type: application/json" \
-d '{"path": "/posts/hello-world", "token": "your-secret"}'
七、常见坑点与排查
7.1 “404 Not Found” 部署后
原因:Vercel 没有正确识别 Nuxt 的 output 目录。
修复:
- 确认
nuxt.config.ts中有nitro: { preset: 'vercel' } - 检查 Vercel Dashboard → Settings → General → Output Directory 是否设为
.output/public - 如果输出目录为空,检查
npm run build是否成功生成了.output/目录
7.2 API 路由返回 500
排查步骤:
- Vercel Dashboard → Logs → 选择你的项目 → 查看最近的 Function Error
- 常见原因:环境变量缺失(
NUXT_DATABASE_URL没配置)、Prisma 生成未执行 - 如果是 Prisma 问题,在构建命令中加
prisma generate:
// package.json
{
"scripts": {
"build": "prisma generate && nuxt build",
"postinstall": "prisma generate"
}
}
7.3 环境变量在客户端读取不到
原因:客户端只能访问 NUXT_PUBLIC_ 前缀的环境变量。
确认:
- 服务端
.env:NUXT_PUBLIC_API_BASE=https://api.example.com - 客户端代码:
useRuntimeConfig().public.apiBase✅ - 服务端代码:
useRuntimeConfig().apiBase❌(非 public 前缀在客户端不可见)
7.4 构建时间过长
- 减少
node_modules体积:npm prune --production后上传 - 启用
swc(Nuxt 3 默认已启用) - 对于 monorepo,使用 Nx/Turborepo 远程缓存
八、从 Demo 到生产
8.1 添加自定义域名
参照 Vercel 国内访问优化指南,配置 www.yourdomain.com + Cloudflare Proxy,确保中国大陆访问稳定。
8.2 添加监控
# 安装 Vercel Analytics
npm install -D @vercel/analytics
// nuxt.config.ts
export default defineNuxtConfig({
plugins: [
{ src: '~/plugins/analytics.client.ts', mode: 'client' },
],
});
// plugins/analytics.client.ts
import { inject } from '@vercel/analytics';
export default defineNuxtPlugin(() => {
inject();
});
8.3 安全头配置
// nuxt.config.ts
export default defineNuxtConfig({
nitro: {
routeRules: {
'/**': {
headers: {
'X-Frame-Options': 'DENY',
'X-Content-Type-Options': 'nosniff',
'Referrer-Policy': 'strict-origin-when-cross-origin',
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'",
},
},
},
},
});
常见问题(FAQ)
Nuxt 2 和 Nuxt 3 在 Vercel 上有什么不同?
Nuxt 3 使用 Nitro 引擎,原生支持 Vercel preset,部署零配置。Nuxt 2 需要 vercel-builder 适配器,且性能不如 Nitro。新项目请用 Nuxt 3。
Nuxt 在 Vercel 上能跑 Edge Functions 吗?
Nuxt 的 Server Routes 默认运行在传统 Serverless Functions(Node.js Runtime)。如果确实需要 Edge Runtime,可以用 Vercel 的独立 Edge Middleware(middleware.ts),与 Nuxt 应用并行部署。
Nuxt 的 useFetch 在 SSR 时请求的是哪里?
在 Vercel 的 SSR 模式下,useFetch('/api/posts') 会在服务器端直接调用 Nitro 内部的 API 路由(不走 HTTP),性能最优。在客户端(hydration 后),useFetch 会走正常的 HTTP 请求。
Vercel 对 Nuxt 的 ISR 支持如何?
完全支持。Nuxt 的 routeRules.isr 在 preset: 'vercel' 下会自动使用 Vercel 的 Incremental Static Regeneration 缓存层,行为和 Next.js ISR 类似。
相关阅读
- Vercel 详解:前端与 AI 应用的一站式云平台
- Vercel 国内访问优化指南
- Vercel 定价与成本详解
- Vercel Edge Functions 深度指南
- Vercel 部署故障排查
- Vercel 专题导航
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。