fix: 改进 Vercel serverless 配置和路径处理

- 修复 vercel.json 构建配置
- 使用 path.join 处理文件路径
- 添加更详细的日志输出
- 改进错误处理和回退机制
- 添加 installCommand 确保正确构建

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
golc 2026-03-04 09:35:08 +00:00
parent 4c01983b10
commit aef3acb6dc
2 changed files with 24 additions and 6 deletions

View File

@ -4,6 +4,7 @@ import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import * as express from 'express'; import * as express from 'express';
import * as bodyParser from 'body-parser'; import * as bodyParser from 'body-parser';
import { join } from 'path';
// 缓存 app 实例,避免每次冷启动都重新创建 // 缓存 app 实例,避免每次冷启动都重新创建
let cachedApp: any; let cachedApp: any;
@ -13,11 +14,22 @@ async function bootstrap() {
const expressApp = express(); const expressApp = express();
// 动态导入模块,支持构建后的路径 // 动态导入模块,支持构建后的路径
const { AppModule } = await import('../dist/app.module.js'); let AppModule;
try {
// 尝试从 dist 目录加载
const distPath = join(process.cwd(), 'dist', 'app.module.js');
AppModule = (await import(distPath)).AppModule;
} catch (error) {
console.error('Failed to load from dist:', error.message);
// 回退到 src 目录
const srcPath = join(process.cwd(), 'src', 'app.module.ts');
AppModule = (await import(srcPath)).AppModule;
}
const app = await NestFactory.create( const app = await NestFactory.create(
AppModule, AppModule,
new ExpressAdapter(expressApp), new ExpressAdapter(expressApp),
{ logger: ['error', 'warn', 'log'] }
); );
// 配置 CORS // 配置 CORS
@ -41,8 +53,9 @@ async function bootstrap() {
// 尝试加载全局过滤器和拦截器(如果存在) // 尝试加载全局过滤器和拦截器(如果存在)
try { try {
const { HttpExceptionFilter } = await import('../dist/common/filters/http-exception.filter.js'); const distCommonPath = join(process.cwd(), 'dist', 'common');
const { TransformInterceptor } = await import('../dist/common/interceptors/transform.interceptor.js'); const { HttpExceptionFilter } = await import(join(distCommonPath, 'filters', 'http-exception.filter.js'));
const { TransformInterceptor } = await import(join(distCommonPath, 'interceptors', 'transform.interceptor.js'));
app.useGlobalFilters(new HttpExceptionFilter()); app.useGlobalFilters(new HttpExceptionFilter());
app.useGlobalInterceptors(new TransformInterceptor()); app.useGlobalInterceptors(new TransformInterceptor());
} catch (error) { } catch (error) {
@ -74,6 +87,8 @@ async function bootstrap() {
await app.init(); await app.init();
cachedApp = expressApp; cachedApp = expressApp;
console.log('NestJS app initialized successfully');
} }
return cachedApp; return cachedApp;
} }
@ -81,13 +96,15 @@ async function bootstrap() {
// Vercel Serverless handler // Vercel Serverless handler
export default async function handler(req: any, res: any) { export default async function handler(req: any, res: any) {
try { try {
console.log(`Request: ${req.method} ${req.url}`);
const app = await bootstrap(); const app = await bootstrap();
app(req, res); app(req, res);
} catch (error) { } catch (error) {
console.error('Handler error:', error); console.error('Handler error:', error);
res.status(500).json({ res.status(500).json({
error: 'Internal Server Error', error: 'Internal Server Error',
message: error.message message: error.message,
stack: process.env.NODE_ENV === 'development' ? error.stack : undefined
}); });
} }
} }

View File

@ -2,7 +2,7 @@
"version": 2, "version": 2,
"builds": [ "builds": [
{ {
"src": "package.json", "src": "api/index.ts",
"use": "@vercel/node" "use": "@vercel/node"
} }
], ],
@ -11,5 +11,6 @@
"src": "/(.*)", "src": "/(.*)",
"dest": "/api/index.ts" "dest": "/api/index.ts"
} }
] ],
"installCommand": "pnpm install && pnpm run build"
} }