From e9d17c72640601b94443734f52664af03ebcd8ea Mon Sep 17 00:00:00 2001 From: npub15skvhry Date: Fri, 15 May 2026 12:53:15 +0330 Subject: [PATCH] feat: minimize container size and caching --- .forgejo | 1 + .gitea/workflows/container-publish.yml | 95 ++++++++++++++++++++++++++ .gitea/workflows/docker-publish.yml | 50 -------------- .github | 1 + Containerfile | 67 ++++++++++++++++++ Dockerfile | 27 -------- package.json | 1 + vite.config.server.ts | 27 ++++++++ 8 files changed, 192 insertions(+), 77 deletions(-) create mode 120000 .forgejo create mode 100644 .gitea/workflows/container-publish.yml delete mode 100644 .gitea/workflows/docker-publish.yml create mode 120000 .github create mode 100644 Containerfile delete mode 100644 Dockerfile create mode 100644 vite.config.server.ts diff --git a/.forgejo b/.forgejo new file mode 120000 index 00000000..7a213d8e --- /dev/null +++ b/.forgejo @@ -0,0 +1 @@ +.gitea \ No newline at end of file diff --git a/.gitea/workflows/container-publish.yml b/.gitea/workflows/container-publish.yml new file mode 100644 index 00000000..411633a4 --- /dev/null +++ b/.gitea/workflows/container-publish.yml @@ -0,0 +1,95 @@ +name: Container Build and Publish + +on: + push: + branches: [ master ] + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + REGISTRY: gitea.coracle.social + +jobs: + build-and-push-image: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + - name: Set Variables + id: set_variables + run: | + # convert everything to lowercase because ghcr repository name must be lowercase + ACTOR="${GITHUB_ACTOR,,}" + REPOSITORY="${GITHUB_REPOSITORY##*/}" + REPOSITORY="${REPOSITORY,,}" + echo "actor=${ACTOR}" >> $GITHUB_OUTPUT + echo "repository=${REPOSITORY}" >> $GITHUB_OUTPUT + shell: bash + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + with: + driver: docker-container + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.PACKAGE_TOKEN }} + + - name: Extract metadata (tags, labels) for nodejs image + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.REGISTRY }}/${{ steps.set_variables.outputs.actor }}/${{ steps.set_variables.outputs.repository }} + tags: | + type=ref,event=branch + type=semver,pattern={{version}} + type=semver,pattern={{major}}.{{minor}} + type=sha,prefix={{branch}}- + type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} + - name: Build and push nodejs-based image + id: push + uses: docker/build-push-action@v5 + with: + context: . + file: ./Containerfile + push: true + target: production-nodejs + platforms: linux/amd64,linux/arm64 + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + #cache-from: type=gha + #cache-to: type=gha,mode=max + + #- name: Extract metadata (tags, labels) for nginx image + # id: meta + # uses: docker/metadata-action@v5 + # with: + # images: ${{ env.REGISTRY }}/${{ steps.set_variables.outputs.actor }}/${{ steps.set_variables.outputs.repository }}-nginx + # tags: | + # type=ref,event=branch + # type=semver,pattern={{version}} + # type=semver,pattern={{major}}.{{minor}} + # type=sha,prefix={{branch}}- + # type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} + #- name: Build and push nginx-based image + # id: push + # uses: docker/build-push-action@v5 + # with: + # context: . + # file: ./Containerfile + # push: true + # target: production-nginx + # platforms: linux/amd64,linux/arm64 + # tags: ${{ steps.meta.outputs.tags }} + # labels: ${{ steps.meta.outputs.labels }} + # cache-from: type=gha + # cache-to: type=gha,mode=max diff --git a/.gitea/workflows/docker-publish.yml b/.gitea/workflows/docker-publish.yml deleted file mode 100644 index 446198d7..00000000 --- a/.gitea/workflows/docker-publish.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Docker - -on: - push: - branches: [master] - -env: - REGISTRY: gitea.coracle.social - IMAGE_NAME: coracle/flotilla - -jobs: - build-and-push-image: - runs-on: ubuntu-latest - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Log in to the Container registry - uses: docker/login-action@v3 - with: - registry: ${{ env.REGISTRY }} - username: hodlbod - password: ${{ secrets.PACKAGE_TOKEN }} - - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - tags: | - type=raw,value=latest,enable=${{ github.ref == 'refs/heads/master' }} - - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 - with: - driver: docker-container - - - name: Build and push Docker image - id: push - uses: docker/build-push-action@v5 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} diff --git a/.github b/.github new file mode 120000 index 00000000..7a213d8e --- /dev/null +++ b/.github @@ -0,0 +1 @@ +.gitea \ No newline at end of file diff --git a/Containerfile b/Containerfile new file mode 100644 index 00000000..bd5fbb20 --- /dev/null +++ b/Containerfile @@ -0,0 +1,67 @@ +# Build and run the Flotilla web server. +# +# docker build -t flotilla . +# docker run -p 3000:3000 flotilla +# +# Pass --build-arg VITE_BUILD_HASH=$(git rev-parse --short HEAD) to stamp the build. +# A .env in the build context is picked up by build.sh for branding config. + + +# https://pnpm.io/docker#example-3-build-on-cicd +FROM node:24-bookworm-slim AS builder +ENV PNPM_HOME="/pnpm" +ENV PATH="$PNPM_HOME:$PATH" +RUN corepack enable + +WORKDIR /app +ENV NODE_OPTIONS=--max_old_space_size=16384 +COPY package.json pnpm-lock.yaml ./ +RUN pnpm i --frozen-lockfile +COPY . . +ARG VITE_BUILD_HASH +RUN pnpm run build +RUN pnpm run build:server + + +FROM nginx:alpine AS production-nginx +COPY --from=builder /app/build /usr/share/nginx/html +RUN cat > /etc/nginx/conf.d/default.conf << 'EOF' +server { + listen 3000; + server_name _; + root /usr/share/nginx/html; + index index.html; + # Enable gzip + gzip on; + gzip_vary on; + gzip_min_length 1024; + gzip_types text/plain text/css text/xml text/javascript application/javascript application/json; + # Security headers + add_header X-Frame-Options "SAMEORIGIN" always; + add_header X-Content-Type-Options "nosniff" always; + add_header X-XSS-Protection "1; mode=block" always; + # https://gist.github.com/dukedorje/01fd7ddbfc8cdac4e02c6105d26ca7fe + location ^~ /_app/immutable { + # gzip_static on; + try_files $uri =404; + expires 1y; + add_header Cache-Control "public, immutable"; + etag on; + access_log off; + expires max; + } + location / { + try_files $uri $uri/ /index.html; + } +} +EOF +EXPOSE 3000 +CMD ["nginx", "-g", "daemon off;"] + +FROM node:lts-slim AS production-nodejs +ENV NODE_ENV=production +WORKDIR /app +COPY --from=builder /app/build /app/build +COPY --from=builder /app/dist-server/server.js /app/server.js +EXPOSE 3000 +CMD ["node", "server.js"] diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index b158d36d..00000000 --- a/Dockerfile +++ /dev/null @@ -1,27 +0,0 @@ -# Build and run the Flotilla web server. -# -# docker build -t flotilla . -# docker run -p 3000:3000 flotilla -# -# Pass --build-arg VITE_BUILD_HASH=$(git rev-parse --short HEAD) to stamp the build. -# A .env in the build context is picked up by build.sh for branding config. - -FROM node:22-bookworm - -RUN npm install -g pnpm@10.33.0 - -WORKDIR /app - -COPY package.json pnpm-lock.yaml ./ - -RUN pnpm i --frozen-lockfile - -ENV NODE_OPTIONS=--max_old_space_size=16384 - -COPY . . - -RUN pnpm run build - -EXPOSE 3000 - -CMD ["node", "server.js"] diff --git a/package.json b/package.json index 9fa9c685..3a7e7077 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "scripts": { "dev": "vite dev", "build": "./build.sh", + "build:server": "vite build --config vite.config.server.ts", "start": "node server.js", "release:android": "./build.sh && cap build android --androidreleasetype APK --signing-type apksigner", "tauri:dev": "tauri dev", diff --git a/vite.config.server.ts b/vite.config.server.ts new file mode 100644 index 00000000..25c2157a --- /dev/null +++ b/vite.config.server.ts @@ -0,0 +1,27 @@ +import { defineConfig } from "vite" +import { builtinModules } from 'module' + +export default defineConfig({ + ssr: { + noExternal: true, // bundle every dependency + }, + build: { + target: 'node24', // match your Node.js version + outDir: 'dist-server', + emptyOutDir: false, // don't wipe the frontend build output + ssr: true, // tells Vite this is a server-side build + minify: 'esbuild', // minify the output + lib: { + entry: 'server.js', // your server entry point + formats: ['es'], + fileName: () => 'server.js', + }, + rollupOptions: { + // Externalize only Node.js built-ins, bundle everything else + external: [ + ...builtinModules, + ...builtinModules.map(m => `node:${m}`), + ], + }, + }, +}) -- 2.52.0