Schritt 4. React 18, TypeScript, Vite 5, Tailwind 4 (CSS-first), Lucide, Zustand; kein Konsta. Quelle in server/ui, Build nach server/web (gitignored), im Abbild von einer eigenen Docker-Stufe gebaut. JEDER KNOPF GIBT RUECKMELDUNG -- und zwar erzwungen, nicht vorgenommen: - api.ts haelt den EINZIGEN fetch und GENAU EINE Fehlerklasse. Der Fivemanage-Fehler war, zwei zu haben: geworfen wurde `new Error`, geprueft auf `instanceof ApiError`, und damit verschwand jeder Fehlschlag lautlos. - store.ts haelt run(): Aktion rein, Erfolgstext rein, und es meldet bei Erfolg diesen und bei Fehlschlag den Text DES DIENSTES. Wer darueber geht, kann keinen stillen Knopf bauen. - Jeder wartende Knopf ist gesperrt und zeigt einen Kreisel. Der zweite Klick eine Sekunde spaeter war der Weg zu neunzehn gleichnamigen Organisationen. - Fehlermeldungen bleiben stehen, bis jemand sie wegklickt. Ein Fehler, der von allein verschwindet, ist einer, den niemand gelesen hat. @vitejs/plugin-react ist auf ^4 festgenagelt: die 6 verlangt vite ^8. In den peerDependencies nachgesehen -- Vite 5.4.21 liegt in der Schnittmenge von plugin-react@4 und @tailwindcss/vite@4. Am laufenden Container nachgemessen: / kommt als text/html, assets/*.js als text/javascript, *.css als text/css (die MIME-Falle aus Schritt 1 traegt), und /tokens, /speicher, /konto liefern dieselbe index.html -- die SPA-Rueckfall- route tut, wofuer sie gebaut wurde. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
84 lines
3.2 KiB
Docker
84 lines
3.2 KiB
Docker
# Das Abbild: ein Prozess, eine Platte, sonst nichts.
|
|
#
|
|
# NODE 22 IST FESTGENAGELT, und das ist kein Zufall. better-sqlite3 ist ein
|
|
# nativer Baustein und laedt beim Installieren eine fertige Binaerdatei
|
|
# herunter (`prebuild-install || node-gyp rebuild`). Fuer 11.10.0 gibt es die
|
|
# nur fuer diese ABI-Versionen:
|
|
#
|
|
# Node 20 -> ABI 115 vorhanden
|
|
# Node 22 -> ABI 127 vorhanden <- wir
|
|
# Node 24 -> ABI 137 FEHLT
|
|
#
|
|
# Wer auf 24 hochzieht, faellt auf node-gyp zurueck, und das braucht python3,
|
|
# make und g++ im Abbild. Der Bau bricht dann ab -- laut und sofort, immerhin.
|
|
# Vor einem Versionssprung also nachsehen, ob es die ABI als Binaerdatei gibt:
|
|
# https://github.com/WiseLibs/better-sqlite3/releases
|
|
#
|
|
# bookworm-slim und nicht alpine: musl-Binaerdateien gibt es zwar auch, aber
|
|
# der glibc-Weg ist der ausgetretene. Das Abbild ist dafuer groesser -- bei
|
|
# einem Container auf dem eigenen Server ist das der guenstigere Tausch.
|
|
|
|
# ------------------------------------------------------------ Abhaengigkeiten
|
|
FROM node:22-bookworm-slim AS deps
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
# Nur was der Betrieb braucht. Hier laeuft prebuild-install und holt die
|
|
# native Binaerdatei fuer diese Node-Version.
|
|
RUN npm ci --omit=dev
|
|
|
|
# --------------------------------------------------------------- Oberflaeche
|
|
# Eigene Stufe, damit ein geaendertes Dashboard nicht den Server neu uebersetzt
|
|
# und umgekehrt. Was hier entsteht, ist reines HTML/CSS/JS -- im Betrieb laeuft
|
|
# davon nichts, es wird nur ausgeliefert.
|
|
FROM node:22-bookworm-slim AS web
|
|
WORKDIR /ui
|
|
COPY ui/package.json ui/package-lock.json ./
|
|
# Hier bewusst OHNE --omit=dev: vite und tsc sind devDependencies, und ohne sie
|
|
# gibt es nichts zu bauen.
|
|
RUN npm ci
|
|
COPY ui/ ./
|
|
# vite.config.ts schreibt nach ../web, also /web. Wer das dort aendert, aendert
|
|
# die Zeile im Betriebsabbild mit.
|
|
RUN npm run build
|
|
|
|
# -------------------------------------------------------------------- Bauen
|
|
FROM node:22-bookworm-slim AS build
|
|
WORKDIR /app
|
|
COPY package.json package-lock.json ./
|
|
RUN npm ci
|
|
COPY tsconfig.json ./
|
|
COPY src ./src
|
|
RUN npm run build
|
|
|
|
# ------------------------------------------------------------------ Betrieb
|
|
FROM node:22-bookworm-slim AS runtime
|
|
ENV NODE_ENV=production
|
|
WORKDIR /app
|
|
|
|
COPY --from=deps /app/node_modules ./node_modules
|
|
COPY --from=build /app/dist ./dist
|
|
COPY package.json ./
|
|
|
|
# Die gebaute Oberflaeche. Der Dienst liefert sie aus, wenn sie da ist, und
|
|
# sagt sonst, dass sie fehlt (siehe index.ts) -- diese Auskunft bleibt als
|
|
# Netz, falls die Stufe oben je leer ausgeht.
|
|
COPY --from=web /web ./web
|
|
|
|
# Ein Ordner fuer Bilder UND media.db, damit eine Sicherung aus genau einem
|
|
# Kopiervorgang ueber ein Volume besteht.
|
|
ENV DATA_DIR=/data
|
|
RUN mkdir -p /data && chown -R node:node /data /app
|
|
|
|
# Nicht als root. Der Dienst nimmt Dateien von aussen entgegen und schreibt sie
|
|
# auf die Platte -- das ist die Stelle, an der man das nicht will.
|
|
USER node
|
|
|
|
ENV PORT=8080
|
|
EXPOSE 8080
|
|
|
|
# Ohne curl im Abbild: Node kann das selbst, fetch ist ab 18 eingebaut.
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
|
|
CMD node -e "fetch('http://127.0.0.1:'+(process.env.PORT||8080)+'/health').then(r=>process.exit(r.ok?0:1)).catch(()=>process.exit(1))"
|
|
|
|
CMD ["node", "dist/index.js"]
|