import { cpSync, mkdirSync } from 'node:fs' import { createRequire } from 'node:module' import { dirname, join } from 'node:path' import { defineConfig, type Plugin } from 'vite' import react from '@vitejs/plugin-react' import tailwindcss from '@tailwindcss/vite' import { VitePWA } from 'vite-plugin-pwa' /** * Die 14 Standardschriften von PDF.js nach public/ kopieren. * * Aeltere PDFs betten Helvetica, Times und Courier nicht ein, sondern setzen * sie voraus. Ohne diese Dateien malt PDF.js mit einer Ersatzschrift – lesbar, * aber Zeilen brechen an anderer Stelle als im Original. * * Kopiert statt eingecheckt: 800 KB fremde Binaerdateien gehoeren nicht in den * Quelltext, und die Fassung soll der Abhaengigkeit folgen. public/pdfjs steht * deshalb in .gitignore. */ function pdfjsStandardFonts(): Plugin { return { name: 'aether-pdfjs-standard-fonts', // Nicht 'buildStart': Im Entwicklungsbetrieb liest der Server public/ // beim Start ein, das Kopieren muss vorher passiert sein. config() { const require = createRequire(import.meta.url) const from = join(dirname(require.resolve('pdfjs-dist/package.json')), 'standard_fonts') const to = join(import.meta.dirname, 'public', 'pdfjs', 'standard_fonts') mkdirSync(to, { recursive: true }) cpSync(from, to, { recursive: true }) }, } } export default defineConfig({ plugins: [ pdfjsStandardFonts(), react(), tailwindcss(), VitePWA({ registerType: 'autoUpdate', workbox: { // Der Service Worker beantwortet jede Navigation aus dem Cache mit // index.html – nötig, damit Adressen wie /admin oder /s/ auch // offline funktionieren. Ohne diese Ausnahmen erwischt er aber auch // Downloads: Ein Klick auf „Download" öffnet eine Navigation zu // /api/v1/files//download, der Worker liefert die Anwendung statt // der Datei, und es passiert sichtbar nichts. navigateFallback: 'index.html', navigateFallbackDenylist: [/^\/api\//, /^\/dav\//, /^\/share\//, /^\/branding\//, /^\/wopi\//], // PDF.js bleibt aussen vor: Betrachter (435 KB), Arbeiter (1,3 MB) // und Standardschriften (800 KB) sind zusammen zweieinhalb Megabyte, // die nur braucht, wer ein PDF oeffnet. Vorab in den Cache zu legen // hiesse, das jeder Installation aufzuladen. // // Offline waere davon ohnehin nichts gewonnen: Die Dokumente selbst // liegen auf dem Server und werden nicht mitgecacht – ein Betrachter // ohne Datei nuetzt nichts. globIgnores: [ '**/pdfjs/standard_fonts/**', '**/pdf.worker*.mjs', '**/PdfViewer-*.js', '**/PdfViewer-*.css', ], maximumFileSizeToCacheInBytes: 3 * 1024 * 1024, }, // Das Manifest liefert der Server (/manifest.webmanifest): Name, Farbe // und Symbol stehen in der Datenbank und sollen dem Admin-Bereich // folgen. Gebaut waeren sie fest verdrahtet, und ein hochgeladenes // Symbol erreichte die installierte App nie. manifest: false, }), ], server: { host: true, // auf allen Interfaces lauschen (IPv4 + IPv6), nötig für VS-Code-Port-Forwarding proxy: { '/api': { target: 'http://localhost:8080', changeOrigin: true, proxyTimeout: 60 * 60 * 1000, timeout: 60 * 60 * 1000, }, '/share': { target: 'http://localhost:8080', changeOrigin: true, }, // Logo, App-Symbol und Manifest kommen ebenfalls vom Backend – ohne // diese beiden Eintraege fehlen sie im Entwicklungsbetrieb. '/branding': { target: 'http://localhost:8080', changeOrigin: true, }, '/manifest.webmanifest': { target: 'http://localhost:8080', changeOrigin: true, }, }, }, test: { environment: 'jsdom', globals: true, setupFiles: './src/test-setup.ts', }, })