feat: 개발 모드 → 배포 모드 전환
- 프론트엔드+백엔드 단일 컨테이너로 통합 (Dockerfile) - Fastify 정적 파일 서빙 + SPA fallback - @fastify/static 추가 - Caddy 프록시 대상 변경 (traeon-frontend → traeon) - 체크박스 w-5/w-0 CSS 충돌 수정 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
92b223eea1
commit
f2070aa8ba
8 changed files with 86 additions and 27 deletions
9
.dockerignore
Normal file
9
.dockerignore
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
node_modules
|
||||
frontend/node_modules
|
||||
backend/node_modules
|
||||
frontend/dist
|
||||
backend/dist
|
||||
logo
|
||||
docs
|
||||
.git
|
||||
*.md
|
||||
20
Dockerfile
Normal file
20
Dockerfile
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
FROM node:20-alpine
|
||||
WORKDIR /app
|
||||
|
||||
# 프론트엔드 빌드
|
||||
COPY frontend/package*.json ./frontend/
|
||||
RUN cd frontend && npm install
|
||||
COPY frontend/ ./frontend/
|
||||
RUN cd frontend && npm run build
|
||||
|
||||
# 백엔드
|
||||
COPY backend/package*.json ./backend/
|
||||
RUN cd backend && npm install --omit=dev
|
||||
COPY backend/ ./backend/
|
||||
|
||||
# 프론트엔드 빌드 결과를 백엔드 dist로 복사
|
||||
RUN cp -r frontend/dist backend/dist
|
||||
|
||||
WORKDIR /app/backend
|
||||
EXPOSE 80
|
||||
CMD ["node", "src/server.js"]
|
||||
|
|
@ -1,4 +1,21 @@
|
|||
# 개발 모드
|
||||
FROM node:20-alpine
|
||||
# 배포 모드
|
||||
FROM node:20-alpine AS base
|
||||
WORKDIR /app
|
||||
CMD ["sh", "-c", "npm install && npm run dev"]
|
||||
|
||||
# 프론트엔드 빌드
|
||||
COPY frontend/package*.json ./frontend/
|
||||
RUN cd frontend && npm ci
|
||||
COPY frontend/ ./frontend/
|
||||
RUN cd frontend && npm run build
|
||||
|
||||
# 백엔드
|
||||
COPY backend/package*.json ./backend/
|
||||
RUN cd backend && npm ci --production
|
||||
COPY backend/ ./backend/
|
||||
|
||||
# 프론트엔드 빌드 결과를 백엔드 dist로 복사
|
||||
RUN cp -r frontend/dist backend/dist
|
||||
|
||||
WORKDIR /app/backend
|
||||
EXPOSE 80
|
||||
CMD ["node", "src/server.js"]
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@fastify/cors": "^11.2.0",
|
||||
"@fastify/static": "^8.0.0",
|
||||
"dayjs": "^1.11.13",
|
||||
"fastify": "^5.2.1",
|
||||
"fastify-plugin": "^5.0.1",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,17 @@
|
|||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
import Fastify from 'fastify';
|
||||
import fastifyCors from '@fastify/cors';
|
||||
import fastifyStatic from '@fastify/static';
|
||||
import config from './config/index.js';
|
||||
import dbPlugin from './plugins/db.js';
|
||||
import trackerPlugin from './plugins/tracker.js';
|
||||
import routes from './routes/index.js';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
export async function buildApp(opts = {}) {
|
||||
const fastify = Fastify({
|
||||
logger: {
|
||||
|
|
@ -33,5 +40,22 @@ export async function buildApp(opts = {}) {
|
|||
return { status: 'ok', timestamp: new Date().toISOString() };
|
||||
});
|
||||
|
||||
// 정적 파일 서빙 (프론트엔드 빌드 결과물)
|
||||
const distPath = path.join(__dirname, '../dist');
|
||||
if (fs.existsSync(distPath)) {
|
||||
await fastify.register(fastifyStatic, {
|
||||
root: distPath,
|
||||
prefix: '/',
|
||||
});
|
||||
|
||||
// SPA fallback
|
||||
fastify.setNotFoundHandler((request, reply) => {
|
||||
if (request.url.startsWith('/api/')) {
|
||||
return reply.code(404).send({ error: 'Not found' });
|
||||
}
|
||||
return reply.sendFile('index.html');
|
||||
});
|
||||
}
|
||||
|
||||
return fastify;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,26 +1,11 @@
|
|||
services:
|
||||
traeon-frontend:
|
||||
build: ./frontend
|
||||
container_name: traeon-frontend
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
volumes:
|
||||
- ./frontend:/app
|
||||
depends_on:
|
||||
- traeon-backend
|
||||
networks:
|
||||
- app
|
||||
restart: unless-stopped
|
||||
|
||||
traeon-backend:
|
||||
build: ./backend
|
||||
container_name: traeon-backend
|
||||
traeon:
|
||||
build: .
|
||||
container_name: traeon
|
||||
labels:
|
||||
- "com.centurylinklabs.watchtower.enable=false"
|
||||
env_file:
|
||||
- .env
|
||||
volumes:
|
||||
- ./backend:/app
|
||||
depends_on:
|
||||
- delivery-tracker
|
||||
networks:
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
# 개발 모드
|
||||
FROM node:20-alpine
|
||||
# 프론트엔드 빌드 전용
|
||||
FROM node:20-alpine AS build
|
||||
WORKDIR /app
|
||||
CMD ["sh", "-c", "npm install --include=dev && npm run dev -- --host 0.0.0.0"]
|
||||
COPY package*.json ./
|
||||
RUN npm ci
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
|
|
|||
|
|
@ -262,10 +262,10 @@ function MainPage({ showForm, setShowForm }) {
|
|||
e.stopPropagation();
|
||||
toggleCheck(parcel.id);
|
||||
}}
|
||||
className={`w-5 h-5 rounded-md border-2 flex items-center justify-center shrink-0 transition-all duration-300 ${
|
||||
className={`h-5 rounded-md border-2 flex items-center justify-center shrink-0 transition-all duration-300 ${
|
||||
deleteMode
|
||||
? "opacity-100 scale-100 mr-0"
|
||||
: "opacity-0 scale-0 w-0 -mr-2"
|
||||
? "w-5 opacity-100 scale-100 mr-0"
|
||||
: "w-0 opacity-0 scale-0 -mr-2"
|
||||
} ${
|
||||
deleteMode && checkedIds.has(parcel.id)
|
||||
? "bg-primary border-primary cursor-pointer"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue