#!/usr/bin/env bash # Baut das Laufzeit-Paket von ProxDeploy – dieselbe Struktur für Docker-Image und LXC-Installer: # # paket/ # app/ Next standalone (server.js, .next, node_modules), dazu public/, catalog/, # prisma/migrations/ – Arbeitsverzeichnis für app und worker # worker/worker.mjs worker als ein Bundle (esbuild); Pakete aus worker/node_modules # worker/migrieren.mjs Migrationen ohne Prisma-CLI # worker/node_modules/ Produktions-Abhängigkeiten, flach (ohne Symlinks) # VERSION # # scripts/paket-bauen.sh [version] → paket/ # scripts/paket-bauen.sh 0.6.0 --tar → zusätzlich proxdeploy-0.6.0.tar.gz set -euo pipefail cd "$(dirname "$0")/.." version="${1:-$(node -p 'require("./package.json").version')}" commit="$(git rev-parse --short HEAD 2>/dev/null || echo unbekannt)" rm -rf paket mkdir -p paket/worker # 1. Web-App (standalone). Version und Commit landen im Build (Seitenleiste, /api/v1/ich). NEXT_PUBLIC_APP_VERSION="$version" NEXT_PUBLIC_GIT_SHA="$commit" pnpm build >/dev/null cp -a .next/standalone paket/app cp -a .next/static paket/app/.next/static cp -a public paket/app/public cp -a catalog paket/app/catalog mkdir -p paket/app/prisma && cp -a prisma/migrations paket/app/prisma/migrations # 2. worker und Migrationslauf als Bundles; eigener Code (inkl. Prisma-Client aus src/generated) # wird gebündelt, Pakete bleiben extern. for eintrag in "src/worker/main.ts:worker.mjs" "src/betrieb/migrieren-start.ts:migrieren.mjs"; do pnpm exec esbuild "${eintrag%%:*}" --bundle --platform=node --format=esm --target=node24 \ --packages=external --log-level=warning \ --define:process.env.NEXT_PUBLIC_APP_VERSION="\"$version\"" \ --define:process.env.NEXT_PUBLIC_GIT_SHA="\"$commit\"" \ --metafile="paket/worker/${eintrag##*:}.meta.json" \ --outfile="paket/worker/${eintrag##*:}" done # 3. Nur die Pakete, die die Bundles wirklich importieren (aus den esbuild-Metadateien), in den # Versionen aus package.json – flach, ohne Build-Skripte. Next, React & Co. braucht der worker nicht. tmp="$(mktemp -d)" node - "$tmp" paket/worker/*.meta.json <<'JS' const fs = require("node:fs"); const [ziel, ...metas] = process.argv.slice(2); const pkg = JSON.parse(fs.readFileSync("package.json", "utf8")); const benoetigt = new Set(); for (const datei of metas) { const meta = JSON.parse(fs.readFileSync(datei, "utf8")); for (const eingabe of Object.values(meta.inputs)) for (const imp of eingabe.imports ?? []) if (imp.external && !imp.path.startsWith("node:")) { const teile = imp.path.split("/"); benoetigt.add(imp.path.startsWith("@") ? teile.slice(0, 2).join("/") : teile[0]); } } const abhaengigkeiten = {}; for (const name of [...benoetigt].sort()) { if (!pkg.dependencies[name]) throw new Error(`${name} wird vom worker importiert, steht aber nicht in dependencies`); // Exakt die Version, die in der Entwicklung installiert ist (aus dem Lockfile aufgelöst). abhaengigkeiten[name] = JSON.parse(fs.readFileSync(`node_modules/${name}/package.json`, "utf8")).version; } fs.writeFileSync(`${ziel}/package.json`, JSON.stringify({ name: "proxdeploy-worker", private: true, type: "module", dependencies: abhaengigkeiten }, null, 2)); console.log(`worker braucht: ${Object.entries(abhaengigkeiten).map(([n, v]) => `${n}@${v}`).join(", ")}`); JS rm -f paket/worker/*.meta.json cp pnpm-workspace.yaml "$tmp/" (cd "$tmp" && pnpm install --prod --ignore-scripts --config.node-linker=hoisted >/dev/null) mv "$tmp/node_modules" paket/worker/node_modules rm -rf "$tmp" echo "$version+$commit" > paket/VERSION echo "paket/ gebaut ($version+$commit, $(du -sh paket | cut -f1))" if [ "${2:-}" = "--tar" ]; then tar -czf "proxdeploy-$version.tar.gz" -C paket . sha256sum "proxdeploy-$version.tar.gz" fi