Understand SwissKnife
Architecture
How SwissKnife is assembled, served and deployed.
SwissKnife is a single client application. It has no application API, database or authentication service.
Browser
→ React application
→ images: Canvas 2D
→ audio / video: FFmpeg WASM (single thread, sequential queue)
→ FFmpeg core: /ffmpeg/ffmpeg-core.js and /ffmpeg/ffmpeg-core.wasmIn Docker production:
Unprivileged Nginx (port 2501)
→ static files from dist/
→ SPA fallback to index.html
→ COOP / COEP / CSP headers (SharedArrayBuffer)Verified stack
| Layer | Current choice |
|---|---|
| Interface | React 19, strict TypeScript |
| Build | Vite 6, Tailwind CSS 4 |
| Images | Canvas API |
| Audio / video | @ffmpeg/ffmpeg 0.12 and local @ffmpeg/core 0.12.6 |
| Container | Node 22 Alpine build stage, Nginx unprivileged 1.27 Alpine at runtime |
| Checks | ESLint, Vitest (npm test), tsc --noEmit |
Two distinct artifacts
| Artifact | Command | Purpose |
|---|---|---|
| Standard product | npm run build | Docker, GHCR and normal deployment |
| Public demo | npm run build:demo | Public Vercel demo only |
The Dockerfile runs npm run build. The product repository's vercel.json runs npm run build:demo. Do not swap them.
Repository Compose files
| File | Image source |
|---|---|
docker-compose.yml | ghcr.io/lucas-lepajollec/swissknife:latest |
docker-compose.build.yml | local build from the Dockerfile |
The default homelab installation pulls the published image instead of rebuilding the checkout every time.