- scripts/pack-bundle.mjs zips dist-native deterministically (sorted paths,
fixed mtimes) into dist/downloads/waiter-bundle-<hash>.zip and writes
waiter-bundle.json {format, version "<APP_VERSION>-<hash12>", file,
sha256 (hex), size, min_shell_build, app_version, built_at}
- src/native/shell.js: MIN_SHELL_BUILD - lowest APK versionCode a bundle
runs in (bump with native changes)
- Dockerfile: node 22; builds web + native bundle + pack (APP_VERSION build
arg, from ${VERSION} in docker-compose.dev.yml)
- vite native mode strips public/downloads from dist-native - the 10.8 MB
APK was being copied into the native build (and would have ended up inside
the next APK); bundle 15 MB → 5 MB
- nginx /downloads/: json/zip types, CORS * (the app reads the manifest from
origin http://localhost), no-cache
- .dockerignore: android/, releases/, dist-native/ out of the build context
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
71 lines
2.2 KiB
JavaScript
71 lines
2.2 KiB
JavaScript
import { rmSync } from 'node:fs'
|
|
import { fileURLToPath } from 'node:url'
|
|
import { defineConfig } from 'vite'
|
|
import react from '@vitejs/plugin-react'
|
|
import { VitePWA } from 'vite-plugin-pwa'
|
|
|
|
// `vite build --mode native` builds the UI bundled inside the Capacitor app:
|
|
// no service worker (the app ships its own files) and a separate output dir so
|
|
// it never mixes with the web build served by the venue's nginx.
|
|
export default defineConfig(({ mode }) => {
|
|
const native = mode === 'native'
|
|
|
|
return {
|
|
build: {
|
|
outDir: native ? 'dist-native' : 'dist',
|
|
},
|
|
server: {
|
|
host: '0.0.0.0',
|
|
port: 5173,
|
|
allowedHosts: ['all'],
|
|
proxy: {
|
|
'/api/ws': {
|
|
target: 'ws://localhost:8000',
|
|
ws: true,
|
|
changeOrigin: true,
|
|
},
|
|
'/api': {
|
|
target: 'http://localhost:8000',
|
|
changeOrigin: true,
|
|
},
|
|
},
|
|
},
|
|
plugins: [
|
|
react(),
|
|
// public/downloads/ holds the APK + UI bundle that venue servers hand out.
|
|
// It belongs in the web build only — never inside the app or its bundle.
|
|
native && {
|
|
name: 'xenia-strip-downloads',
|
|
closeBundle() {
|
|
rmSync(fileURLToPath(new URL('./dist-native/downloads', import.meta.url)), { recursive: true, force: true })
|
|
},
|
|
},
|
|
VitePWA({
|
|
disable: native,
|
|
registerType: 'prompt',
|
|
manifest: {
|
|
name: 'Xenia',
|
|
short_name: 'Xenia',
|
|
start_url: '/',
|
|
display: 'standalone',
|
|
background_color: '#0f172a',
|
|
theme_color: '#0f172a',
|
|
icons: [
|
|
{ src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
|
|
{ src: '/icons/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'maskable' },
|
|
{ src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any' },
|
|
{ src: '/icons/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'maskable' },
|
|
],
|
|
},
|
|
workbox: {
|
|
globPatterns: ['**/*.{js,css,html,ico,png,svg}'],
|
|
runtimeCaching: [],
|
|
},
|
|
devOptions: {
|
|
enabled: false,
|
|
},
|
|
}),
|
|
],
|
|
}
|
|
})
|