fuzzyworld

explodorama / files / vite.config.ts

vite.config.ts

Blame: the commit that last changed each line · file · history

9ed991c9 2026-11-03 Pavel Safronov1import { defineConfig } from 'vitest/config'
5551eb37 2026-10-20 Pavel Safronov2import { qrcode } from 'vite-plugin-qrcode'
0b25f1ef 2026-10-24 Pavel Safronov3import { execSync } from 'node:child_process'
351348d1 2026-11-04 Pavel Safronov4import { existsSync, readFileSync } from 'node:fs'
2f667e95 2026-10-27 Pavel Safronov5import fuzzyworld from 'fuzzyworld-tools/vite'
bb3823d2 2026-10-31 Pavel Safronov6import { UNRELEASED, VERSION } from './src/changelog.ts'
5551eb37 2026-10-20 Pavel Safronov7
8/**
9 * Relative asset paths by default, so the same build works wherever Pages puts it:
10 * at https://<user>.gitlab.io/<project>/ or at the root of a generated domain. Set BASE to
11 * override. `??` would not catch BASE="", so `||`.
12 */
13const base = process.env.BASE || './'
14
0b25f1ef 2026-10-24 Pavel Safronov15/** A git command's output, or '' where there is no git (the menu then leaves the commit out). */
16function git(args: string): string {
17 try {
18 return execSync(`git ${args}`, { encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim()
19 } catch {
20 return ''
21 }
22}
23
24// The commit the game was built from, shown in the menu with the version. Vite hands VITE_*
25// variables to the game as import.meta.env. DIRTY: the build has uncommitted changes (in dev).
26process.env.VITE_COMMIT = git('rev-parse --short HEAD')
27process.env.VITE_COMMIT_DIRTY = git('status --porcelain') ? '1' : ''
28
bb3823d2 2026-10-31 Pavel Safronov29// Which copy is being built (src/channel.ts): `fw deploy --as explodorama-next` builds the next
30// one, from `main`, for anyone who wants to try what isn't released. Anything else is the released copy.
31const next = (process.env.FW_APP ?? '').endsWith('-next')
32process.env.VITE_CHANNEL = next ? 'next' : 'stable'
b89399da 2026-11-01 Pavel Safronov33// Where each copy lives, from package.json (`homepage`, `nextHomepage`): the menu shows and links them (src/channel.ts).
34const pkg = JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')) as { homepage: string; nextHomepage: string }
35// (Assigning undefined would make the text "undefined".)
36if (pkg.homepage) process.env.VITE_HOME_URL = pkg.homepage
37if (pkg.nextHomepage) process.env.VITE_NEXT_URL = pkg.nextHomepage
bb3823d2 2026-10-31 Pavel Safronov38
5551eb37 2026-10-20 Pavel Safronov39export default defineConfig({
40 base,
52d68b59 2026-10-24 Pavel Safronov41 // `npm run dev` and `npm run preview` bind to every interface (--host) so a phone on the same
42 // Wi-Fi can open the game; this prints a scannable QR of that network URL alongside it.
bb3823d2 2026-10-31 Pavel Safronov43 plugins: [
44 fuzzyworld(),
45 qrcode(),
351348d1 2026-11-04 Pavel Safronov46 // Dev only (Q103): `replays/<name>.json`, made by `npm run report-replay`, served as /__replay/<name>.json
47 // for the replay page (`?replay=<name>`). Nothing in a build.
48 {
49 name: 'report-replays',
50 configureServer(server) {
51 server.middlewares.use('/__replay', (req, res) => {
52 const name = (req.url ?? '').replace(/^\//, '').replace(/\.json$/, '')
53 const file = new URL(`./replays/${name}.json`, import.meta.url)
54 if (!/^[\w.-]+$/.test(name) || !existsSync(file)) {
55 res.statusCode = 404
56 return res.end('no such replay')
57 }
58 res.setHeader('content-type', 'application/json')
59 res.end(readFileSync(file))
60 })
61 },
62 },
bb3823d2 2026-10-31 Pavel Safronov63 // The next copy tells the released one what is coming, for its "Try it early" teaser
64 // (src/ui/whatsnew.ts): next.json beside the game.
65 {
66 name: 'next-info',
67 generateBundle() {
68 if (!next) return
69 const info = { version: VERSION, commit: process.env.VITE_COMMIT, unreleased: UNRELEASED }
70 this.emitFile({ type: 'asset', fileName: 'next.json', source: JSON.stringify(info) })
71 },
72 },
73 ],
52d68b59 2026-10-24 Pavel Safronov74 // In `npm run dev`, the game's console output and uncaught errors, from any device (a phone on
75 // the Wi-Fi too), are printed in this terminal (user request, 2026-10-23: a crash on the phone
76 // showed nothing anywhere). Caught errors are logged with their stack by src/devlog.ts.
77 server: { forwardConsole: { unhandledErrors: true, logLevels: ['error', 'warn', 'info', 'log'] } },
5551eb37 2026-10-20 Pavel Safronov78 // Not `public/`: GitLab Pages requires its artifact to be a directory named `public`, and
79 // `mv dist public` moves dist *inside* an existing `public/` instead of renaming it.
80 publicDir: 'static',
644cfd0b 2026-10-20 Pavel Safronov81 // Sprites stay separate files rather than being inlined into the script: the art for enemies and
82 // pickups that aren't in the game yet then costs nothing until something draws it.
83 build: { target: 'es2022', assetsInlineLimit: 0 },
9ed991c9 2026-11-03 Pavel Safronov84 // The decoy demo tests replay seeds 1-6 turn by turn: ~3 s here, over vitest's default 5 s on
85 // the slower CI runner (CI was red from 2026-11-01 for that reason alone).
86 test: { testTimeout: 30000 },
5551eb37 2026-10-20 Pavel Safronov87})