chore: add Dockerfile and docker-compose with static file serving
Multi-stage Docker build (web → server → production). Fastify serves React build in production with SPA fallback. Docker Compose with volume for SQLite persistence. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,7 +1,10 @@
|
||||
import { createServer } from 'node:http';
|
||||
import { join } from 'node:path';
|
||||
import { existsSync } from 'node:fs';
|
||||
import Fastify from 'fastify';
|
||||
import cors from '@fastify/cors';
|
||||
import { PORT } from './config.js';
|
||||
import fastifyStatic from '@fastify/static';
|
||||
import { PORT, NODE_ENV } from './config.js';
|
||||
import { runMigrations } from './db/migrate.js';
|
||||
import { healthRoutes } from './routes/health.js';
|
||||
import { shipRoutes } from './routes/ships.js';
|
||||
@@ -27,8 +30,26 @@ const start = async () => {
|
||||
await app.register(shipRoutes);
|
||||
await app.register(weaponRoutes);
|
||||
|
||||
// In production, serve the React build as static files
|
||||
const webDistPath = join(process.cwd(), 'web-dist');
|
||||
if (NODE_ENV === 'production' && existsSync(webDistPath)) {
|
||||
await app.register(fastifyStatic, {
|
||||
root: webDistPath,
|
||||
prefix: '/',
|
||||
wildcard: false,
|
||||
});
|
||||
|
||||
// SPA fallback: non-API GET requests return index.html
|
||||
app.setNotFoundHandler((request, reply) => {
|
||||
if (request.method === 'GET' && !request.url.startsWith('/api')) {
|
||||
return reply.sendFile('index.html');
|
||||
}
|
||||
reply.code(404).send({ error: 'Not found' });
|
||||
});
|
||||
}
|
||||
|
||||
await app.listen({ port: PORT, host: '0.0.0.0' });
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
console.log(`Server running on port ${PORT} (${NODE_ENV})`);
|
||||
} catch (err) {
|
||||
app.log.error(err);
|
||||
process.exit(1);
|
||||
|
||||
Reference in New Issue
Block a user