nordic-skating / local-littlejs / files / vite.config.ts
Branch local-littlejs · default branch · all branches
vite.config.ts
c90277fa 2026-10-09 Pavel Safronov | 1 | import { defineConfig } from 'vite' |
bd311616 2026-10-10 Pavel Safronov | 2 | import { VitePWA } from 'vite-plugin-pwa' |
c90277fa 2026-10-09 Pavel Safronov | 3 | import { qrcode } from 'vite-plugin-qrcode' |
| 4 | ||
| 5 | /** | |
| 6 | * Relative asset paths by default, so the same build works wherever Pages puts it: | |
| 7 | * at https://<user>.gitlab.io/<project>/ or, with unique domains on, at the root of a | |
| 8 | * generated domain. Set BASE to override. `??` would not catch BASE="", so `||`. | |
| 9 | */ | |
| 10 | const base = process.env.BASE || './' | |
| 11 | ||
| 12 | export default defineConfig({ | |
| 13 | base, | |
| 14 | // `npm run dev` binds to every interface (--host) so a phone on the same Wi-Fi can | |
| 15 | // open the app; this prints a scannable QR of that network URL alongside it. | |
bd311616 2026-10-10 Pavel Safronov | 16 | plugins: [ |
| 17 | qrcode(), | |
| 18 | // What makes the app installable: a manifest that says what it is called and how it | |
| 19 | // opens, and a service worker that keeps a copy of it, so that it opens with no | |
| 20 | // network at all. Nothing in the app is fetched after that; the lake is computed. | |
| 21 | VitePWA({ | |
| 22 | // A new version is taken up the next time the app is opened, without asking. | |
| 23 | registerType: 'autoUpdate', | |
| 24 | includeAssets: ['apple-touch-icon.png', 'favicon.png', 'favicon-dark.png'], | |
| 25 | manifest: { | |
| 26 | name: 'Nordic Skating', | |
| 27 | short_name: 'Skating', | |
| 28 | description: 'An endless skate over thin black ice that sings under every stride.', | |
| 29 | // No browser bars, and no status bar where the phone allows that: only the lake. | |
| 30 | display: 'fullscreen', | |
| 31 | display_override: ['fullscreen', 'standalone'], | |
| 32 | background_color: '#0b1a24', | |
| 33 | theme_color: '#0b1a24', | |
| 34 | // Relative, for the same reason as `base`: both resolve against the manifest's | |
| 35 | // own address, so the installed app belongs to wherever it was deployed. | |
| 36 | start_url: '.', | |
| 37 | scope: '.', | |
| 38 | icons: [ | |
| 39 | { src: 'icon-192.png', sizes: '192x192', type: 'image/png' }, | |
| 40 | { src: 'icon-512.png', sizes: '512x512', type: 'image/png' }, | |
| 41 | { src: 'icon-maskable-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' }, | |
| 42 | ], | |
| 43 | }, | |
1ee103b4 2026-10-11 Pavel Safronov | 44 | // The pictures on the buttons are kept on the phone with the rest: without them |
| 45 | // named here they would be fetched, and missing with no network. | |
| 46 | workbox: { cleanupOutdatedCaches: true, globPatterns: ['**/*.{js,css,html,png}'] }, | |
bd311616 2026-10-10 Pavel Safronov | 47 | // Not while developing: a service worker handing back yesterday's code is the last |
| 48 | // thing wanted there. | |
| 49 | devOptions: { enabled: false }, | |
| 50 | }), | |
| 51 | ], | |
c90277fa 2026-10-09 Pavel Safronov | 52 | // Vite's static directory is `static/`, not the default `public/`, because GitLab |
| 53 | // Pages requires its artifact to be a directory named `public` — and `mv dist public` | |
| 54 | // does not rename when `public/` already exists, it moves dist *inside* it. | |
| 55 | publicDir: 'static', | |
| 56 | build: { | |
| 57 | target: 'es2022', | |
| 58 | // Three.js alone is ~515 kB. Raise the threshold past it so the warning stays | |
| 59 | // meaningful for chunks that are large by accident. | |
| 60 | chunkSizeWarningLimit: 600, | |
| 61 | }, | |
| 62 | }) |