diff --git a/.github/workflows/web.yml b/.github/workflows/web.yml index 63b4722dd..c38e67d5f 100644 --- a/.github/workflows/web.yml +++ b/.github/workflows/web.yml @@ -3,140 +3,73 @@ name: Web - Build & Deploy on: push: branches: - - main + - next paths: - .github/workflows/web.yml - web/** pull_request: - types: [opened, synchronize, reopened, closed] branches: - - main + - next paths: - .github/workflows/web.yml - web/** +env: + CONTAINER_REGISTRY: ghcr.io + CONTAINER_REPOSITORY: ${{ github.repository_owner }}/filterlists-web + CONTAINER_IMAGE_TAG_UNIQUE: ${{ github.run_id }} + WORKING_DIRECTORY: ./web + jobs: - build_and_deploy_staging: - name: Build & Deploy to Staging + build: + name: Build & Push Docker Image runs-on: ubuntu-latest permissions: - contents: read - id-token: write - - if: github.event_name == 'pull_request' && github.event.action != 'closed' - - environment: - name: staging-web - url: ${{ steps.builddeploy.outputs.static_web_app_url }} + packages: write steps: - name: Checkout uses: actions/checkout@v4 - - name: Setup Node - uses: actions/setup-node@v4 + - name: Log in to the Container registry + if: github.event_name == 'push' + uses: docker/login-action@v3 with: - node-version: lts/* - cache: npm - cache-dependency-path: web/package-lock.json + registry: ${{ env.CONTAINER_REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Install - run: npm ci - working-directory: ./web - - - name: Run Prettier - run: npm run prettier:check - working-directory: ./web - - - name: Run ESLint - run: npm run eslint:check - working-directory: ./web - - - name: Build - run: npm run build - working-directory: ./web - - - name: Copy Static Web App Config - run: cp staticwebapp.config.json build/ - working-directory: ./web - - - name: Deploy - id: builddeploy - uses: Azure/static-web-apps-deploy@v1 + - name: Build & Push Docker Image + uses: docker/build-push-action@v5 with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_STAPP_FILTERLISTS_PROD }} - repo_token: ${{ secrets.GITHUB_TOKEN }} - action: upload - app_location: ./web/build - output_location: "" - skip_app_build: true - continue-on-error: true + context: ${{ env.WORKING_DIRECTORY }} + push: ${{ github.event_name == 'push' }} + tags: | + ${{ env.CONTAINER_REGISTRY }}/${{ env.CONTAINER_REPOSITORY }}:${{ env.CONTAINER_IMAGE_TAG_UNIQUE }} + ${{ env.CONTAINER_REGISTRY }}/${{ env.CONTAINER_REPOSITORY }}:latest - build_and_deploy_production: - name: Build & Deploy to Production + deploy: + name: Deploy runs-on: ubuntu-latest - permissions: - contents: read - id-token: write + needs: build if: github.event_name == 'push' + env: + AZURE_WEBAPP_NAME: app-filterlists-web-prod + environment: - name: production-web - url: https://filterlists.com + name: production-web-next + url: https://next.filterlists.com steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: Setup Node - uses: actions/setup-node@v4 + - name: Deploy to Azure Web App + uses: azure/webapps-deploy@v3 with: - node-version: lts/* - cache: npm - cache-dependency-path: web/package-lock.json - - - name: Install - run: npm ci - working-directory: ./web - - - name: Build - run: npm run build - working-directory: ./web - - - name: Copy Static Web App Config - run: cp staticwebapp.config.json build/ - working-directory: ./web - - - name: Deploy - id: builddeploy - uses: Azure/static-web-apps-deploy@v1 - with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_STAPP_FILTERLISTS_PROD }} - repo_token: ${{ secrets.GITHUB_TOKEN }} - action: upload - app_location: ./web/build - output_location: "" - skip_app_build: true - - close_pull_request: - name: Close Pull Request - - runs-on: ubuntu-latest - - permissions: - contents: read - - if: github.event_name == 'pull_request' && github.event.action == 'closed' - - steps: - - name: Close Pull Request - uses: Azure/static-web-apps-deploy@v1 - with: - azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_STAPP_FILTERLISTS_PROD }} - action: close - app_location: ./web + app-name: ${{ env.AZURE_WEBAPP_NAME }} + publish-profile: ${{ secrets.AZURE_WEBAPP_PUBLISH_PROFILE_APP_FILTERLISTS_WEB_PROD }} + images: ${{ env.CONTAINER_REGISTRY }}/${{ env.CONTAINER_REPOSITORY }}:${{ env.CONTAINER_IMAGE_TAG_UNIQUE }} \ No newline at end of file diff --git a/web/Dockerfile b/web/Dockerfile new file mode 100644 index 000000000..b1fff4da9 --- /dev/null +++ b/web/Dockerfile @@ -0,0 +1,68 @@ +# https://github.com/vercel/next.js/blob/canary/examples/with-docker/Dockerfile + +# syntax=docker.io/docker/dockerfile:1 + +FROM node:18-alpine AS base + +# Install dependencies only when needed +FROM base AS deps +# 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 +WORKDIR /app + +# Install dependencies based on the preferred package manager +COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ +RUN \ + if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ + elif [ -f package-lock.json ]; then npm ci; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ + else echo "Lockfile not found." && exit 1; \ + fi + + +# Rebuild the source code only when needed +FROM base AS builder +WORKDIR /app +COPY --from=deps /app/node_modules ./node_modules +COPY . . + +# Next.js collects completely anonymous telemetry data about general usage. +# Learn more here: https://nextjs.org/telemetry +# Uncomment the following line in case you want to disable telemetry during the build. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN \ + if [ -f yarn.lock ]; then yarn run build; \ + elif [ -f package-lock.json ]; then npm run build; \ + elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ + else echo "Lockfile not found." && exit 1; \ + fi + +# Production image, copy all the files and run next +FROM base AS runner +WORKDIR /app + +ENV NODE_ENV=production +# Uncomment the following line in case you want to disable telemetry during runtime. +ENV NEXT_TELEMETRY_DISABLED=1 + +RUN addgroup --system --gid 1001 nodejs +RUN adduser --system --uid 1001 nextjs + +COPY --from=builder /app/public ./public + +# Automatically leverage output traces to reduce image size +# https://nextjs.org/docs/advanced-features/output-file-tracing +COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ +COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static + +USER nextjs + +EXPOSE 3000 + +ENV PORT=3000 + +# server.js is created by next build from the standalone output +# https://nextjs.org/docs/pages/api-reference/config/next-config-js/output +ENV HOSTNAME="0.0.0.0" +CMD ["node", "server.js"] diff --git a/web/next.config.ts b/web/next.config.ts index e9ffa3083..ed2357811 100644 --- a/web/next.config.ts +++ b/web/next.config.ts @@ -2,6 +2,7 @@ import type { NextConfig } from "next"; const nextConfig: NextConfig = { /* config options here */ + output: "standalone", }; export default nextConfig;