fix(ui): down-level build target to es2019 for old Android WebViews
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).
This commit is contained in:
Ilia Denisov
2026-07-04 12:58:57 +02:00
parent 8c55b2d239
commit 6dfd5203d7
2 changed files with 8 additions and 2 deletions
+1 -1
View File
@@ -162,7 +162,7 @@
['numeric separator 1_000', 'return 1_000', 75],
['dynamic import()', 'return import("")', 63],
];
var synPre = section('JS SYNTAX (esbuild target is es2022 — the bundle uses these)');
var synPre = section('JS SYNTAX (engine feature ceiling — first NO dates the engine)');
function mark(ok) {
return ok ? 'OK ' : 'NO ';
}