feat: SPA build + serving im Dockerfile und server.ts
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled
Some checks failed
Deploy Discord Bot / deploy (push) Has been cancelled
This commit is contained in:
18
dockerfile
18
dockerfile
@@ -12,20 +12,30 @@ ENV PATH="/usr/src/app/node_modules/.bin:${PATH}"
|
||||
ENV DATABASE_URL=postgresql://user:pass@localhost:5432/papo?schema=public
|
||||
ENV PRISMA_IGNORE_ENV_LOAD=true
|
||||
|
||||
# Install dependencies (inkl. dev)
|
||||
# Install backend dependencies
|
||||
COPY package*.json ./
|
||||
RUN npm ci --include=dev
|
||||
|
||||
# Ensure prisma CLI available globally (avoids path issues)
|
||||
RUN npm install -g prisma@5.4.2
|
||||
# Install frontend dependencies
|
||||
COPY frontend/package*.json ./frontend/
|
||||
RUN npm --prefix frontend ci
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Build frontend
|
||||
RUN npm run build:web
|
||||
|
||||
# Ensure prisma CLI available globally (avoids path issues)
|
||||
RUN npm install -g prisma@5.4.2
|
||||
|
||||
# Generate Prisma client (explicit schema path)
|
||||
RUN prisma generate --schema=src/database/schema.prisma
|
||||
|
||||
# Build backend
|
||||
RUN npm run build
|
||||
|
||||
# Optional: show versions in build log
|
||||
RUN node -v && npm -v && npx prisma -v
|
||||
|
||||
CMD ["npm", "run", "dev"]
|
||||
CMD ["npm", "start"]
|
||||
|
||||
@@ -2,6 +2,7 @@ import express from 'express';
|
||||
import session from 'express-session';
|
||||
import cookieParser from 'cookie-parser';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import authRouter from './routes/auth';
|
||||
import dashboardRouter from './routes/dashboard';
|
||||
import apiRouter from './routes/api';
|
||||
@@ -11,7 +12,6 @@ export function createWebServer() {
|
||||
const app = express();
|
||||
const basePath = env.webBasePath || '/ucp';
|
||||
const dashboardPath = `${basePath}/dashboard`;
|
||||
const apiPath = `${basePath}/api`;
|
||||
app.use(express.json({ limit: '5mb' }));
|
||||
app.use(cookieParser());
|
||||
app.use(
|
||||
@@ -24,12 +24,10 @@ export function createWebServer() {
|
||||
|
||||
const mount = (suffix: string) => (basePath ? `${basePath}${suffix}` : suffix);
|
||||
app.use(mount('/auth'), authRouter);
|
||||
app.use(dashboardPath, dashboardRouter);
|
||||
app.use(mount('/api'), apiRouter);
|
||||
// fallback mounts if proxy strips base path
|
||||
if (basePath) {
|
||||
app.use('/api', apiRouter);
|
||||
app.use('/dashboard', dashboardRouter);
|
||||
}
|
||||
|
||||
// Redirect bare auth calls to the prefixed path when a base path is set
|
||||
@@ -37,9 +35,31 @@ export function createWebServer() {
|
||||
app.use('/auth', (_req, res) => res.redirect(`${basePath}${_req.originalUrl}`));
|
||||
}
|
||||
|
||||
// Landing pages
|
||||
app.get('/', (_req, res) => res.redirect(dashboardPath));
|
||||
app.get(basePath || '/', (_req, res) => {
|
||||
// Serve React SPA static assets
|
||||
const frontendDist = path.join(process.cwd(), 'frontend', 'dist');
|
||||
|
||||
// If SPA exists, it takes precedence for GET dashboard routes
|
||||
if (fs.existsSync(path.join(frontendDist, 'index.html'))) {
|
||||
const spaHtml = fs.readFileSync(path.join(frontendDist, 'index.html'), 'utf-8');
|
||||
const configScript = `window.__PAPO__ = ${JSON.stringify({
|
||||
baseRoot: basePath,
|
||||
baseApi: mount('/api'),
|
||||
baseAuth: mount('/auth'),
|
||||
baseDashboard: dashboardPath
|
||||
})}`;
|
||||
|
||||
app.use(basePath || '/', express.static(frontendDist));
|
||||
|
||||
app.get(`${dashboardPath}(/*)?`, (_req, res) => {
|
||||
res.type('html').send(spaHtml.replace('__PAPO_CONFIG__', configScript));
|
||||
});
|
||||
|
||||
app.get(mount('/'), (_req, res) => {
|
||||
res.redirect(dashboardPath);
|
||||
});
|
||||
} else {
|
||||
// Legacy landing page when SPA is not built
|
||||
app.get(mount('/'), (_req, res) => {
|
||||
res.send(`
|
||||
<!doctype html>
|
||||
<html lang="de">
|
||||
@@ -67,6 +87,14 @@ export function createWebServer() {
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
}
|
||||
|
||||
// Old dashboard router – only handles POST/non-GET routes when SPA is active,
|
||||
// or all routes when SPA is inactive
|
||||
app.use(dashboardPath, dashboardRouter);
|
||||
if (basePath) {
|
||||
app.use('/dashboard', dashboardRouter);
|
||||
}
|
||||
|
||||
app.use(mount('/static'), express.static(path.join(process.cwd(), 'static')));
|
||||
return app;
|
||||
|
||||
Reference in New Issue
Block a user