6dfd5203d7
CI / changes (pull_request) Successful in 1s
CI / unit (pull_request) Has been skipped
CI / integration (pull_request) Has been skipped
CI / ui (pull_request) Successful in 1m5s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 2m34s
The es2022 build target shipped optional chaining / nullish coalescing verbatim (esbuild does not down-level syntax below the configured target), so an old Android System WebView — captured as Chromium 66 in the Telegram/VK in-app WebView on Android 9, via the boot diagnostic — rejected the bundle with "Uncaught SyntaxError: Unexpected token ?" at main-*.js:2, the module never ran (no .app-shell, #app empty) and the SPA showed a white screen. Firefox/Gecko on the same device, which ships its own current engine, rendered the SPA fine. Lower build.target to es2019 so esbuild down-levels the es2020+ syntax the old engine cannot parse (?., ??, private fields, static blocks, numeric separators). Verified the emitted main bundle no longer contains ?./?? and the mock e2e (Chromium + WebKit) still passes. The boot-diagnostic JS-SYNTAX header is relabelled accordingly. esbuild lowers syntax only, not runtime APIs; the app's own production source uses none beyond this floor (mock-only helpers are tree-shaken). A graceful "update your WebView" fallback and any runtime-API polyfills follow once the on-device re-test confirms the parse fix (and @vitejs/plugin-legacy stays in reserve for even older engines).
82 lines
4.0 KiB
TypeScript
82 lines
4.0 KiB
TypeScript
import { resolve } from 'node:path';
|
|
import { defineConfig, type Plugin } from 'vite';
|
|
import { svelte } from '@sveltejs/vite-plugin-svelte';
|
|
|
|
/**
|
|
* stripBootDiag removes the temporary on-device boot-diagnostic block from index.html — the span
|
|
* between the `<!-- BOOT-DIAG:START -->` and `<!-- BOOT-DIAG:END -->` markers. That block is a
|
|
* full-screen ES5 overlay meant only for the production build shipped to the test contour, so it
|
|
* is dropped from every non-production build: the `mock` e2e (whose first taps the overlay would
|
|
* intercept) and the dev server. It is wired only when mode !== 'production'. Remove this plugin
|
|
* together with the index.html block once the Android WebView diagnosis is finished — it must
|
|
* never reach master / production.
|
|
*/
|
|
function stripBootDiag(): Plugin {
|
|
return {
|
|
name: 'strip-boot-diag',
|
|
transformIndexHtml(html) {
|
|
return html.replace(/\s*<!-- BOOT-DIAG:START[\s\S]*?BOOT-DIAG:END -->/g, '');
|
|
},
|
|
};
|
|
}
|
|
|
|
// The edge Connect service is scrabble.edge.v1.Gateway; the gateway serves it over
|
|
// h2c on :8081 by default. In dev we proxy the RPC path so the browser (which can
|
|
// not speak h2c directly) talks to the dev server on the same origin. In `mock`
|
|
// mode the app runs entirely against an in-memory fake transport — no gateway,
|
|
// no backend, no Postgres — which is what `pnpm start` launches.
|
|
const RPC_PREFIX = '/scrabble.edge.v1.Gateway';
|
|
|
|
export default defineConfig(({ mode }) => ({
|
|
// Relative asset base so the one build serves under any path — the gateway maps the
|
|
// Telegram Mini App to /telegram/ (the hash router is path-agnostic).
|
|
base: './',
|
|
define: {
|
|
// App version shown on the About screen, injected at build time from `git describe`
|
|
// via a Docker build-arg. Falls back to "dev" for a plain local/mock build,
|
|
// so a missing build-arg never breaks the build.
|
|
__APP_VERSION__: JSON.stringify(process.env.VITE_APP_VERSION || 'dev'),
|
|
},
|
|
// The boot-diagnostic overlay ships only in the production build (the test contour); it is
|
|
// stripped from the dev server and the mock e2e build, where a full-screen overlay would
|
|
// intercept Playwright's taps. See stripBootDiag / the index.html BOOT-DIAG block.
|
|
plugins: [svelte(), ...(mode !== 'production' ? [stripBootDiag()] : [])],
|
|
server: {
|
|
port: 5173,
|
|
proxy:
|
|
mode === 'mock'
|
|
? undefined
|
|
: {
|
|
[RPC_PREFIX]: {
|
|
target: process.env.GATEWAY_URL || 'http://localhost:8081',
|
|
changeOrigin: true,
|
|
},
|
|
},
|
|
},
|
|
build: {
|
|
// Down-level to es2019 so an old Android System WebView (seen: Telegram/VK in-app WebView on
|
|
// Chromium 66, Android 9) can parse the bundle — esbuild lowers es2020+ syntax (?., ??, private
|
|
// fields, static blocks, …) that Chrome 66 rejects with "Unexpected token ?", which left the SPA
|
|
// on a white screen. esbuild lowers syntax only, not runtime APIs; the app's own source uses
|
|
// none beyond this floor (the mock-only helpers are tree-shaken from production). Reach for
|
|
// @vitejs/plugin-legacy if runtime-API polyfills for even older engines turn out to be needed.
|
|
target: 'es2019',
|
|
// Emit sourcemaps everywhere except the production build. A shipped `.map`
|
|
// carries full `sourcesContent` — the entire TypeScript/Svelte source — and the
|
|
// gateway/landing images serve `dist/` verbatim, so production maps would expose
|
|
// the whole client source at the edge. Dev and the `mock` e2e build
|
|
// (`vite build --mode mock`) keep maps for debugging; the production `vite build`
|
|
// (the Docker image build) drops them.
|
|
sourcemap: mode !== 'production',
|
|
// Two entries: the game SPA (index.html, served at /app/ + /telegram/) and the
|
|
// public landing page (landing.html, served at /). Assets are shared in dist/assets/, and
|
|
// the relative base lets one build serve under any path.
|
|
rollupOptions: {
|
|
input: {
|
|
main: resolve(import.meta.dirname, 'index.html'),
|
|
landing: resolve(import.meta.dirname, 'landing.html'),
|
|
},
|
|
},
|
|
},
|
|
}));
|