diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..01a1ae4 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,24 @@ +.DS_Store +.git +.gitignore +.gitea +.claude +.next +.next-test +.vercel +node_modules +coverage +test-results +playwright-report +blob-report +*.tsbuildinfo +next-env.d.ts +npm-debug.log* +yarn-debug.log* +yarn-error.log* +.env +.env*.local +Dockerfile +docker-compose*.yml +docker-compose*.yaml +README.md diff --git a/.gitea/workflows/dev.yml b/.gitea/workflows/dev.yml new file mode 100644 index 0000000..656cb8d --- /dev/null +++ b/.gitea/workflows/dev.yml @@ -0,0 +1,22 @@ +name: dev + +on: + push: + branches: + - master + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - name: Write env file + run: | + test -n "${{ secrets.ENV_DEV }}" + umask 077 + printf '%s\n' "${{ secrets.ENV_DEV }}" > .env + + - name: Deploy + run: docker compose -f docker-compose.dev.yml up -d --build --remove-orphans diff --git a/.gitignore b/.gitignore index 367dbf9..ef70964 100644 --- a/.gitignore +++ b/.gitignore @@ -34,8 +34,7 @@ yarn-debug.log* yarn-error.log* # local env files -.env -.env*.local +.env* # vercel .vercel diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1f1e4dc --- /dev/null +++ b/Dockerfile @@ -0,0 +1,55 @@ +# syntax=docker/dockerfile:1 +FROM oven/bun:1.3.5-alpine AS base +WORKDIR /app +ENV NEXT_TELEMETRY_DISABLED=1 + +# -------------------------- +# Stage 1: Dependencies +# -------------------------- +FROM base AS dependencies +COPY package.json bun.lock ./ +RUN --mount=type=cache,target=/root/.bun/install/cache \ + bun install --frozen-lockfile + +# -------------------------- +# Stage 2: Build +# -------------------------- +FROM base AS builder +ENV NODE_ENV=production + +ARG NEXT_PUBLIC_API_URL +ARG NEXT_PUBLIC_WS_URL +ARG NEXT_PUBLIC_MOCK_WS=false + +ENV NEXT_PUBLIC_API_URL=${NEXT_PUBLIC_API_URL} +ENV NEXT_PUBLIC_WS_URL=${NEXT_PUBLIC_WS_URL} +ENV NEXT_PUBLIC_MOCK_WS=${NEXT_PUBLIC_MOCK_WS} + +COPY --from=dependencies /app/node_modules ./node_modules +COPY . . +RUN bun run build + +# -------------------------- +# Stage 3: Start +# -------------------------- +FROM node:22-alpine AS runner + +ENV NODE_ENV=production +ENV NEXT_TELEMETRY_DISABLED=1 +ENV PORT=3000 +ENV HOSTNAME=0.0.0.0 + +RUN addgroup --system --gid 1001 nodejs \ + && adduser --system --uid 1001 nextjs \ + && apk add --no-cache dumb-init + +WORKDIR /app + +COPY --from=builder --chown=nextjs:nodejs /app/public ./public +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs +EXPOSE 3000 + +CMD ["dumb-init", "node", "server.js"] diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml new file mode 100644 index 0000000..90416d2 --- /dev/null +++ b/docker-compose.dev.yml @@ -0,0 +1,28 @@ +services: + frontend: + image: cofee-frontend:dev + container_name: cofee_frontend + build: + context: . + dockerfile: Dockerfile + env_file: + - .env + restart: unless-stopped + environment: + NODE_ENV: production + NEXT_TELEMETRY_DISABLED: "1" + PORT: 3000 + HOSTNAME: 0.0.0.0 + networks: + - proxy + labels: + - "traefik.enable=true" + - "traefik.docker.network=proxy" + - "traefik.http.routers.cofee_frontend.rule=Host(`app.trimgu.ru`)" + - "traefik.http.routers.cofee_frontend.entrypoints=websecure" + - "traefik.http.routers.cofee_frontend.service=cofee_frontend" + - "traefik.http.services.cofee_frontend.loadbalancer.server.port=3000" + +networks: + proxy: + external: true diff --git a/next.config.mjs b/next.config.mjs index 60324e8..abc3464 100644 --- a/next.config.mjs +++ b/next.config.mjs @@ -6,6 +6,7 @@ const dirname = path.dirname(fileURLToPath(import.meta.url)) const stylesPath = path.join(dirname, "src/shared/styles") const nextConfig = { distDir: process.env.NEXT_TEST_DIR ?? ".next", + output: "standalone", images: { remotePatterns: [ {