mirror of
https://github.com/Lifeforge-app/lifeforge.git
synced 2026-06-28 06:46:24 +00:00
feat: refactor Docker setup and improve build process (WIP)
This commit is contained in:
@@ -62,39 +62,16 @@ services:
|
||||
db-init:
|
||||
condition: service_completed_successfully
|
||||
|
||||
client-builder:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/client-builder/Dockerfile
|
||||
args:
|
||||
- VITE_API_HOST=/api
|
||||
container_name: lifeforge-client-builder
|
||||
environment:
|
||||
- DOCKER_MODE=true
|
||||
- VITE_API_HOST=/api
|
||||
volumes:
|
||||
- ./apps:/app/apps
|
||||
- ./locales:/app/locales
|
||||
- client-dist:/output
|
||||
depends_on:
|
||||
db-init:
|
||||
condition: service_completed_successfully
|
||||
|
||||
client:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: docker/client/Dockerfile
|
||||
args:
|
||||
- VITE_API_HOST=/api
|
||||
container_name: lifeforge-client
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "80:80"
|
||||
volumes:
|
||||
- client-dist:/usr/share/nginx/html
|
||||
depends_on:
|
||||
client-builder:
|
||||
condition: service_completed_successfully
|
||||
server:
|
||||
condition: service_started
|
||||
|
||||
volumes:
|
||||
client-dist:
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ============================================
|
||||
# Client Builder - On-demand client rebuilds
|
||||
# ============================================
|
||||
FROM oven/bun:alpine
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Install all dependencies
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile --ignore-scripts --linker isolated
|
||||
|
||||
# Set environment
|
||||
ENV DOCKER_MODE=true
|
||||
|
||||
# Copy entrypoint script
|
||||
COPY docker/client-builder/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
ENTRYPOINT ["/entrypoint.sh"]
|
||||
@@ -1,18 +0,0 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
echo "=== LifeForge Client Builder ==="
|
||||
|
||||
# Generate module registry
|
||||
echo "Generating module registry..."
|
||||
cd /app && bun forge modules gen-registry
|
||||
|
||||
# Build client
|
||||
echo "Building client..."
|
||||
cd /app/client && bun run build
|
||||
|
||||
# Copy to output volume
|
||||
echo "Copying build to output..."
|
||||
cp -r /app/client/dist/* /output/
|
||||
|
||||
echo "=== Client Build Complete ==="
|
||||
@@ -1,8 +1,28 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ============================================
|
||||
# Client - Static file server (Nginx only)
|
||||
# Build is handled by client-builder service
|
||||
# Builder stage - build client and tools
|
||||
# ============================================
|
||||
FROM oven/bun:alpine AS builder
|
||||
|
||||
# Accept build arg for API host
|
||||
ARG VITE_API_HOST=/api
|
||||
ENV VITE_API_HOST=$VITE_API_HOST
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Install dependencies
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile --linker isolated
|
||||
|
||||
# Build client
|
||||
RUN cd /app/client && bun run build
|
||||
|
||||
# ============================================
|
||||
# Production stage - Nginx static server
|
||||
# ============================================
|
||||
FROM nginx:alpine
|
||||
|
||||
@@ -12,12 +32,12 @@ RUN apk add --no-cache curl
|
||||
# Copy nginx config for SPA routing and API proxying
|
||||
COPY docker/client/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Create directory for static files (will be mounted from volume)
|
||||
RUN mkdir -p /usr/share/nginx/html
|
||||
# Copy built client from builder
|
||||
COPY --from=builder /app/client/dist /usr/share/nginx/html
|
||||
|
||||
EXPOSE 80
|
||||
|
||||
# Health check - verify nginx is responding
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||||
CMD curl -f http://localhost/ || exit 1
|
||||
|
||||
|
||||
@@ -6,7 +6,28 @@
|
||||
FROM ghcr.io/muchobien/pocketbase:latest AS pocketbase
|
||||
|
||||
# ============================================
|
||||
# DB Init Container - Generates and applies migrations
|
||||
# Builder stage - build forge CLI
|
||||
# ============================================
|
||||
FROM oven/bun:alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Install dependencies
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile --linker isolated
|
||||
|
||||
# Build forge CLI
|
||||
RUN cd /app/tools && bun run build
|
||||
|
||||
# Collect only schema files to staging directory
|
||||
RUN mkdir -p /schemas && \
|
||||
find /app/server/src/lib -name "schema.ts" -exec sh -c 'mkdir -p /schemas/$(dirname ${1#/app/}) && cp "$1" /schemas/$(dirname ${1#/app/})/' _ {} \;
|
||||
|
||||
# ============================================
|
||||
# Production stage - minimal runtime
|
||||
# ============================================
|
||||
FROM oven/bun:alpine
|
||||
|
||||
@@ -15,19 +36,25 @@ COPY --from=pocketbase /usr/local/bin/pocketbase /usr/local/bin/pocketbase
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy source
|
||||
COPY . .
|
||||
# Copy ONLY bundled forge CLI (no node_modules!)
|
||||
COPY --from=builder /app/tools/dist/forge.js ./forge.js
|
||||
|
||||
# Install all dependencies
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile --linker isolated
|
||||
# Copy server schema files needed for migration generation
|
||||
COPY --from=builder /schemas/server/src/lib ./server/src/lib
|
||||
|
||||
# Copy shared package (built) for schema imports
|
||||
COPY --from=builder /app/shared/dist ./shared/dist
|
||||
COPY --from=builder /app/shared/package.json ./shared/package.json
|
||||
|
||||
# Install minimal dependencies for schema evaluation
|
||||
RUN echo '{"dependencies":{"zod":"^4.0.0"}}' > package.json && bun install
|
||||
|
||||
# Set environment for Docker mode
|
||||
ENV DOCKER_MODE=true
|
||||
ENV PB_DIR=/pb_data
|
||||
ENV PB_BINARY_PATH=/usr/local/bin/pocketbase
|
||||
|
||||
# Copy entrypoint script
|
||||
# Copy entrypoint
|
||||
COPY docker/db-init/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
|
||||
@@ -7,8 +7,8 @@ echo "Generating database migrations..."
|
||||
# Ensure the migrations directory exists
|
||||
mkdir -p /pb_data/pb_migrations
|
||||
|
||||
# Generate migrations
|
||||
cd /app && bun run forge db push
|
||||
# Generate and apply migrations using bundled forge CLI
|
||||
cd /app && bun forge.js db push
|
||||
|
||||
echo "Migrations generated successfully!"
|
||||
echo "Migrations applied successfully!"
|
||||
echo "=== DB Init Complete ==="
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
# ============================================
|
||||
# Builder stage - contains build dependencies
|
||||
# Builder stage - build server bundle
|
||||
# ============================================
|
||||
FROM oven/bun:alpine AS builder
|
||||
|
||||
@@ -9,18 +9,24 @@ RUN apk update && apk add git
|
||||
|
||||
WORKDIR /lifeforge
|
||||
|
||||
# Copy all files
|
||||
# Copy source
|
||||
COPY . .
|
||||
|
||||
# Install all dependencies for build
|
||||
# Install dependencies
|
||||
RUN --mount=type=cache,target=/root/.bun/install/cache \
|
||||
bun install --frozen-lockfile --linker isolated
|
||||
|
||||
# Build types (gen-registry runs at runtime now via bun start)
|
||||
RUN cd /lifeforge/server && bun run types
|
||||
# Build server bundle
|
||||
RUN cd /lifeforge/server && bun run build
|
||||
|
||||
# Create cleaned package.json without workspace deps for production install
|
||||
RUN bun -e "const pkg = require('./server/package.json'); \
|
||||
delete pkg.dependencies.shared; \
|
||||
delete pkg.devDependencies; \
|
||||
require('fs').writeFileSync('./server/package.docker.json', JSON.stringify(pkg, null, 2))"
|
||||
|
||||
# ============================================
|
||||
# Production stage - minimal runtime image
|
||||
# Production stage - minimal runtime
|
||||
# ============================================
|
||||
FROM oven/bun:alpine AS production
|
||||
|
||||
@@ -29,18 +35,21 @@ RUN apk add --no-cache curl
|
||||
|
||||
WORKDIR /lifeforge
|
||||
|
||||
# Copy only necessary files from builder
|
||||
# Note: apps/ and locales/ are mounted as volumes, not copied
|
||||
COPY --from=builder /lifeforge/node_modules ./node_modules
|
||||
COPY --from=builder /lifeforge/server ./server
|
||||
COPY --from=builder /lifeforge/shared ./shared
|
||||
COPY --from=builder /lifeforge/packages ./packages
|
||||
COPY --from=builder /lifeforge/tools ./tools
|
||||
COPY --from=builder /lifeforge/package.json ./package.json
|
||||
COPY --from=builder /lifeforge/bun.lock ./bun.lock
|
||||
COPY --from=builder /lifeforge/tsconfig.json ./tsconfig.json
|
||||
# Copy ONLY bundled server (no node_modules!)
|
||||
COPY --from=builder /lifeforge/server/dist ./server/dist
|
||||
|
||||
# Copy entrypoint script
|
||||
# Copy server source for @functions imports (modules import from @functions/*)
|
||||
COPY --from=builder /lifeforge/server/src ./server/src
|
||||
|
||||
# Copy shared package for module imports
|
||||
COPY --from=builder /lifeforge/shared/dist ./shared/dist
|
||||
COPY --from=builder /lifeforge/shared/package.json ./shared/package.json
|
||||
|
||||
# Install server dependencies for module loading (using cleaned package.json without workspace deps)
|
||||
COPY --from=builder /lifeforge/server/package.docker.json ./package.json
|
||||
RUN bun install --production
|
||||
|
||||
# Copy entrypoint
|
||||
COPY docker/server/entrypoint.sh /entrypoint.sh
|
||||
RUN chmod +x /entrypoint.sh
|
||||
|
||||
|
||||
@@ -8,7 +8,50 @@ until wget -q --spider http://db:8090/api/health 2>/dev/null; do
|
||||
done
|
||||
echo "PocketBase is ready!"
|
||||
|
||||
# Start the server
|
||||
# Create symlinks for server path aliases so modules can resolve @functions/*, @lib/*, etc.
|
||||
mkdir -p /lifeforge/node_modules
|
||||
ln -sf /lifeforge/server/src/core/functions /lifeforge/node_modules/@functions
|
||||
ln -sf /lifeforge/server/src/lib /lifeforge/node_modules/@lib
|
||||
ln -sf /lifeforge/server/src/core /lifeforge/node_modules/@core
|
||||
ln -sf /lifeforge/server/src/core/constants.ts /lifeforge/node_modules/@constants
|
||||
ln -sf /lifeforge/server/src/core/schema /lifeforge/node_modules/@schema
|
||||
ln -sf /lifeforge/shared /lifeforge/node_modules/shared
|
||||
|
||||
# Install module-specific dependencies (skip workspace deps that fail)
|
||||
echo "Installing module dependencies..."
|
||||
for dir in /lifeforge/apps/*/; do
|
||||
if [ -f "${dir}package.json" ]; then
|
||||
modname=$(basename "$dir")
|
||||
# Only install if node_modules doesn't exist or is empty
|
||||
if [ ! -d "${dir}node_modules" ] || [ -z "$(ls -A ${dir}node_modules 2>/dev/null)" ]; then
|
||||
echo "Installing deps for $modname..."
|
||||
# Create temp package.json without workspace deps, install, then restore
|
||||
cd "$dir"
|
||||
if [ -f package.json ]; then
|
||||
# Remove workspace deps before install
|
||||
bun -e "
|
||||
const fs = require('fs');
|
||||
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf-8'));
|
||||
const original = JSON.stringify(pkg, null, 2);
|
||||
fs.writeFileSync('package.json.bak', original);
|
||||
if (pkg.dependencies) {
|
||||
for (const [k,v] of Object.entries(pkg.dependencies)) {
|
||||
if (v.startsWith('workspace:')) delete pkg.dependencies[k];
|
||||
}
|
||||
}
|
||||
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2));
|
||||
" 2>/dev/null || true
|
||||
bun install --production 2>/dev/null || true
|
||||
# Restore original package.json
|
||||
if [ -f package.json.bak ]; then
|
||||
mv package.json.bak package.json
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "Module dependencies installed."
|
||||
|
||||
echo "Starting server..."
|
||||
cd /lifeforge/server
|
||||
exec bun run start
|
||||
exec bun dist/server.js
|
||||
|
||||
Reference in New Issue
Block a user