fix: 完全修复 Vercel 部署配置

核心修复:
- 从 src 导入模块而非 dist(让 TypeScript 编译器处理)
- vercel.json 路由指向构建后的 dist/api/index.js
- 简化导入逻辑,移除动态路径拼接
- 本地构建测试通过

技术细节:
- api/index.ts 从 ../src/app.module 导入
- NestJS 构建会将其编译到 dist/api/index.js
- Vercel 执行构建后直接使用编译结果
- CORS 设置为 origin: true 允许所有来源

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
golc 2026-03-04 09:39:57 +00:00
parent 84007475c3
commit 78e73fcb8f
2 changed files with 10 additions and 27 deletions

View File

@ -4,7 +4,9 @@ import { ValidationPipe } from '@nestjs/common';
import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger'; import { DocumentBuilder, SwaggerModule } from '@nestjs/swagger';
import express from 'express'; import express from 'express';
import bodyParser from 'body-parser'; import bodyParser from 'body-parser';
import { join } from 'path';
// 从源码导入TypeScript 会编译到 dist
import { AppModule } from '../src/app.module';
// 缓存 app 实例,避免每次冷启动都重新创建 // 缓存 app 实例,避免每次冷启动都重新创建
let cachedApp: any; let cachedApp: any;
@ -13,19 +15,6 @@ async function bootstrap() {
if (!cachedApp) { if (!cachedApp) {
const expressApp = express(); const expressApp = express();
// 动态导入模块,支持构建后的路径
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),
@ -34,11 +23,7 @@ async function bootstrap() {
// 配置 CORS // 配置 CORS
app.enableCors({ app.enableCors({
origin: [ origin: true, // 允许所有来源
'https://tradingadvfrontend.vercel.app',
'http://localhost:8000',
'http://localhost:3030',
],
credentials: true, credentials: true,
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'], methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH', 'OPTIONS'],
allowedHeaders: [ allowedHeaders: [
@ -51,11 +36,10 @@ async function bootstrap() {
], ],
}); });
// 尝试加载全局过滤器和拦截器(如果存在) // 尝试加载全局过滤器和拦截器
try { try {
const distCommonPath = join(process.cwd(), 'dist', 'common'); const { HttpExceptionFilter } = await import('../src/common/filters/http-exception.filter');
const { HttpExceptionFilter } = await import(join(distCommonPath, 'filters', 'http-exception.filter.js')); const { TransformInterceptor } = await import('../src/common/interceptors/transform.interceptor');
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) {

View File

@ -2,15 +2,14 @@
"version": 2, "version": 2,
"builds": [ "builds": [
{ {
"src": "api/index.ts", "src": "package.json",
"use": "@vercel/node" "use": "@vercel/node"
} }
], ],
"routes": [ "routes": [
{ {
"src": "/(.*)", "src": "/(.*)",
"dest": "/api/index.ts" "dest": "/dist/api/index.js"
} }
], ]
"installCommand": "pnpm install && pnpm run build"
} }