如何在Express/NestJS单体后端部署Next.js静态导出产物?
解决Next.js 13.2静态导出部署+Express/NestJS单体服务器方案
先澄清静态产物的结构问题
执行next build && next export后,静态产物默认生成在out目录下,根路由对应的就是out/index.html,其他路由会以out/xxx/index.html的形式存在。直接查看out目录的文件结构就能找到这些文件,大概率是你没找对目录位置。
另外要检查next.config.js的配置是否正确,确保output: 'export'放在顶层配置里:
/** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', // 其他配置项... } module.exports = nextConfig
一、Express实现单体服务器(处理API+托管SPA)
1. 安装依赖
确保已安装express和serve-static:
npm install express serve-static
2. 编写服务器代码(示例文件:server.js)
const express = require('express'); const serveStatic = require('serve-static'); const path = require('path'); const app = express(); const PORT = process.env.PORT || 3000; // 托管Next.js静态导出产物 app.use(serveStatic(path.join(__dirname, 'out'), { index: ['index.html'], })); // 处理API请求示例 app.get('/api/hello', (req, res) => { res.json({ message: 'Hello from Express API!' }); }); // SPA路由 fallback:所有未匹配的路由返回根index.html app.get('*', (req, res) => { res.sendFile(path.join(__dirname, 'out', 'index.html')); }); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
3. 启动服务器
node server.js
二、NestJS实现单体服务器(处理API+托管SPA)
1. 安装依赖
安装@nestjs/serve-static:
npm install @nestjs/serve-static
2. 配置静态托管(修改app.module.ts)
import { Module } from '@nestjs/common'; import { ServeStaticModule } from '@nestjs/serve-static'; import { join } from 'path'; import { AppController } from './app.controller'; import { AppService } from './app.service'; @Module({ imports: [ ServeStaticModule.forRoot({ rootPath: join(__dirname, '..', 'out'), // 指向Next.js导出的out目录 exclude: ['/api*'], // 排除API路由,交给NestJS处理 }), ], controllers: [AppController], providers: [AppService], }) export class AppModule {}
3. 添加SPA Fallback中间件
创建spa-fallback.middleware.ts:
import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response } from 'express'; import { join } from 'path'; @Injectable() export class SpaFallbackMiddleware implements NestMiddleware { use(req: Request, res: Response, next: () => void) { // 非API、非静态文件请求,返回index.html if (!req.path.startsWith('/api') && !req.path.includes('.')) { res.sendFile(join(__dirname, '..', 'out', 'index.html')); } else { next(); } } }
在app.module.ts中注册中间件:
import { MiddlewareConsumer, Module, NestModule } from '@nestjs/common'; import { SpaFallbackMiddleware } from './spa-fallback.middleware'; // 其他导入项... @Module({ // 已有配置... }) export class AppModule implements NestModule { configure(consumer: MiddlewareConsumer) { consumer.apply(SpaFallbackMiddleware).forRoutes('*'); } }
4. 编写API示例(app.controller.ts)
import { Controller, Get } from '@nestjs/common'; @Controller() export class AppController { @Get('api/hello') getHello(): { message: string } { return { message: 'Hello from NestJS API!' }; } }
5. 启动NestJS服务器
npm run start:prod
关键注意事项
- Next.js静态导出模式下,不能使用Server Components、内置API Routes、图片优化等依赖服务器的功能,这些会在导出时失效,所有API逻辑必须放在Express/NestJS中实现。
- 确保
next build && next export执行无报错,否则out目录可能生成不完整。
内容的提问来源于stack exchange,提问作者victor.ja
相关产品推荐
相关产品推荐

