diff --git a/apps/web/next.config.js b/apps/web/next.config.js index 2026cce50..8ca3bb666 100644 --- a/apps/web/next.config.js +++ b/apps/web/next.config.js @@ -12,6 +12,7 @@ ENV_FILES.forEach((file) => { /** @type {import('next').NextConfig} */ const config = { + output: process.env.DOCKER_OUTPUT ? 'standalone' : undefined, experimental: { serverActionsBodySizeLimit: '50mb', }, diff --git a/docker/Dockerfile b/docker/Dockerfile index a50726eff..ecdd3b91b 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,53 +1,86 @@ +########################### +# BASE CONTAINER # +########################### FROM node:18-alpine AS base -# Install dependencies only when needed -FROM base AS production_deps -WORKDIR /app - -# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. -RUN apk add --no-cache libc6-compat - -# Copy our current monorepo -COPY . . - -RUN npm ci --production - -# Install dependencies only when needed +########################### +# BUILDER CONTAINER # +########################### FROM base AS builder -WORKDIR /app # Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. RUN apk add --no-cache libc6-compat +RUN apk add --no-cache jq +WORKDIR /app -# Copy our current monorepo COPY . . +RUN TURBO_VERSION="$(npm list --package-lock-only --json turbo | jq -r '.dependencies.turbo.version')" +RUN npm install -g "turbo@$TURBO_VERSION" + +# Outputs to the /out folder +# source: https://turbo.build/repo/docs/reference/command-line-reference/prune#--docker +RUN turbo prune --scope=@documenso/web --docker + +########################### +# INSTALLER CONTAINER # +########################### +FROM base AS installer + +# Check https://github.com/nodejs/docker-node/tree/b4117f9333da4138b03a546ec926ef50a31506c3#nodealpine to understand why libc6-compat might be needed. +RUN apk add --no-cache libc6-compat +RUN apk add --no-cache jq +# Required for node_modules/aws-crt +RUN apk add --no-cache make cmake g++ +WORKDIR /app + # Disable husky from installing hooks ENV HUSKY 0 +ENV DOCKER_OUTPUT 1 +ENV NEXT_TELEMETRY_DISABLED 1 + +# Uncomment and use build args to enable remote caching +# ARG TURBO_TEAM +# ENV TURBO_TEAM=$TURBO_TEAM +# ARG TURBO_TOKEN +# ENV TURBO_TOKEN=$TURBO_TOKEN + +# First install the dependencies (as they change less often) +COPY .gitignore .gitignore +COPY --from=builder /app/out/json/ . +COPY --from=builder /app/out/package-lock.json ./package-lock.json RUN npm ci -RUN npm run build --workspaces +# Then copy all the source code (as it changes more often) +COPY --from=builder /app/out/full/ . +# Finally copy the turbo.json file so that we can run turbo commands +COPY turbo.json turbo.json -# Production image, copy all the files and run next +RUN TURBO_VERSION="$(npm list --package-lock-only --json turbo | jq -r '.dependencies.turbo.version')" +RUN npm install -g "turbo@$TURBO_VERSION" + +RUN turbo run build --filter=@documenso/web... + +########################### +# RUNNER CONTAINER # +########################### FROM base AS runner + WORKDIR /app -ENV NODE_ENV production -ENV NEXT_TELEMETRY_DISABLED 1 - +# Don't run production as root RUN addgroup --system --gid 1001 nodejs RUN adduser --system --uid 1001 nextjs +USER nextjs -COPY --from=production_deps --chown=nextjs:nodejs /app/node_modules ./node_modules -COPY --from=production_deps --chown=nextjs:nodejs /app/package-lock.json ./package-lock.json +COPY --from=installer /app/apps/web/next.config.js . +COPY --from=installer /app/apps/web/package.json . -COPY --from=builder --chown=nextjs:nodejs /app/apps/web/package.json ./package.json -COPY --from=builder --chown=nextjs:nodejs /app/apps/web/public ./public -COPY --from=builder --chown=nextjs:nodejs /app/apps/web/.next ./.next +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/standalone ./ +COPY --from=installer --chown=nextjs:nodejs /app/apps/web/.next/static ./apps/web/.next/static +COPY --from=installer --chown=nextjs:nodejs /app/apps/web/public ./apps/web/public -EXPOSE 3000 - -ENV PORT 3000 - -CMD ["npm", "run", "start"] +CMD node apps/web/server.js diff --git a/docker/compose-test.yml b/docker/compose-test.yml new file mode 100644 index 000000000..e401aaf8f --- /dev/null +++ b/docker/compose-test.yml @@ -0,0 +1,32 @@ +name: documenso_test +services: + database: + image: postgres:15 + environment: + - POSTGRES_USER=documenso + - POSTGRES_PASSWORD=password + - POSTGRES_DB=documenso + ports: + - 54322:5432 + + inbucket: + image: inbucket/inbucket + # ports: + # - 9000:9000 + # - 2500:2500 + # - 1100:1100 + + documenso: + build: + context: ../ + dockerfile: docker/Dockerfile + depends_on: + - database + - inbucket + env_file: + - ../.env.example + environment: + - NEXT_PRIVATE_DATABASE_URL=postgres://documenso:password@database:5432/documenso + - NEXT_PRIVATE_DIRECT_DATABASE_URL=postgres://documenso:password@database:5432/documenso + ports: + - 3000:3000 diff --git a/packages/prisma/helper.ts b/packages/prisma/helper.ts index 865e16239..3acd113fc 100644 --- a/packages/prisma/helper.ts +++ b/packages/prisma/helper.ts @@ -23,6 +23,11 @@ export const getDatabaseUrl = () => { process.env.NEXT_PRIVATE_DIRECT_DATABASE_URL = process.env.POSTGRES_URL_NON_POOLING; } + // If we don't have a database URL, we can't normalize it. + if (!process.env.NEXT_PRIVATE_DATABASE_URL) { + return undefined; + } + // We change the protocol from `postgres:` to `https:` so we can construct a easily // mofifiable URL. const url = new URL(process.env.NEXT_PRIVATE_DATABASE_URL.replace('postgres://', 'https://')); diff --git a/packages/prisma/package.json b/packages/prisma/package.json index bd33db657..2fb01a6ac 100644 --- a/packages/prisma/package.json +++ b/packages/prisma/package.json @@ -8,6 +8,7 @@ "build": "prisma generate", "format": "prisma format", "clean": "rimraf node_modules", + "post-install": "prisma generate", "prisma:generate": "prisma generate", "prisma:migrate-dev": "prisma migrate dev", "prisma:migrate-deploy": "prisma migrate deploy",