Refactor Docker setup for minimal image and update build scripts; adjust static asset serving in production
All checks were successful
Build and Push Docker Image / build-and-push (push) Successful in 2m0s

This commit is contained in:
Cameron Redmore 2025-08-08 17:02:32 +01:00
parent 363e1540e0
commit 20d6a8d577
No known key found for this signature in database
6 changed files with 47 additions and 21 deletions

View file

@ -57,11 +57,11 @@ jobs:
org.opencontainers.image.revision=${{ github.sha }} org.opencontainers.image.revision=${{ github.sha }}
org.opencontainers.image.ref.name=${{ github.ref_name }} org.opencontainers.image.ref.name=${{ github.ref_name }}
- name: Build and push Docker image - name: Build and push minimal Docker image
uses: docker/build-push-action@v5 uses: docker/build-push-action@v5
with: with:
context: . context: .
file: ./Dockerfile file: ./Dockerfile # Uses the Alpine-based minimal container
push: true push: true
tags: ${{ steps.meta.outputs.tags }} # Use tags from metadata step tags: ${{ steps.meta.outputs.tags }} # Use tags from metadata step
labels: ${{ steps.meta.outputs.labels }} # Use labels from metadata step labels: ${{ steps.meta.outputs.labels }} # Use labels from metadata step

View file

@ -12,26 +12,32 @@ RUN bun install --frozen-lockfile
# Copy source code and configuration files # Copy source code and configuration files
COPY . . COPY . .
# Build the application with Vite # Build the frontend with Vite and compile the server to executable
RUN bun run build RUN bun run build
# Production stage # Minimal production stage using Alpine
FROM oven/bun:latest FROM alpine:latest
# Install CA certificates for HTTPS requests and glibc compatibility
RUN apk --no-cache add ca-certificates tzdata gcompat
WORKDIR /app WORKDIR /app
# Copy package files # Copy the compiled executable from the build stage (Linux build will not have .exe extension)
COPY package.json bun.lock* ./ COPY --from=builder /app/dist/server /app/server
# Install only production dependencies # Copy the built frontend assets (but ensure we don't overwrite the server executable)
RUN bun install --frozen-lockfile --production COPY --from=builder /app/dist/*.html /app/dist/
COPY --from=builder /app/dist/assets /app/dist/assets
# Copy built application and server from build stage # Make the server executable
COPY --from=builder /app/dist ./dist RUN chmod +x /app/server
COPY src/server.ts ./src/server.ts
# Expose the port # Expose the port
EXPOSE 3000 EXPOSE 3000
# Start the application # Set environment to production
CMD ["bun", "run", "prod"] ENV NODE_ENV=production
# Start the application using the compiled executable
CMD ["/app/server"]

View file

@ -5,8 +5,11 @@
"type": "module", "type": "module",
"scripts": { "scripts": {
"start": "bun src/server.ts", "start": "bun src/server.ts",
"dev": "concurrently \"bun run --hot src/server.ts\" \"vite build --watch\"", "dev": "concurrently \"bun run --hot src/server.ts\" \"vite\"",
"build": "vite build", "build": "vite build && bun build src/server.ts --compile --outfile dist/server",
"build:frontend": "vite build",
"build:server": "bun build src/server.ts --compile --outfile dist/server",
"test:executable": "npm run build && NODE_ENV=production ./dist/server.exe",
"preview": "vite preview", "preview": "vite preview",
"prod": "NODE_ENV=production bun src/server.ts" "prod": "NODE_ENV=production bun src/server.ts"
}, },

View file

@ -1,3 +0,0 @@
onlyBuiltDependencies:
- '@tailwindcss/oxide'
- esbuild

View file

@ -1,5 +1,6 @@
import { Elysia, t } from 'elysia'; import { Elysia, t } from 'elysia';
import { staticPlugin } from '@elysiajs/static'; import { staticPlugin } from '@elysiajs/static';
import path from 'path';
// Song data interface // Song data interface
interface LastSong { interface LastSong {
@ -87,9 +88,16 @@ setInterval(checkAndUpdateSong, 1000);
// Initial fetch // Initial fetch
checkAndUpdateSong(); checkAndUpdateSong();
// Determine static assets path - adjust for compiled executable
const assetsPath = process.env.NODE_ENV === 'production'
? path.join(path.dirname(process.execPath || __dirname), 'dist')
: 'dist';
console.log('Serving static assets from:', assetsPath);
const app = new Elysia() const app = new Elysia()
.use(staticPlugin({ .use(staticPlugin({
assets: 'dist', assets: assetsPath,
prefix: '' prefix: ''
})) }))
.ws('/music', { .ws('/music', {

View file

@ -13,4 +13,16 @@ export default defineConfig({
}, },
}) })
], ],
server: {
port: 5173,
host: 'localhost',
proxy: {
// Proxy the backend WebSocket/API on /music to the Bun server
'/music': {
target: 'http://localhost:3000',
changeOrigin: true,
ws: true,
},
},
},
}) })