Skip to main content

Legacy browser support for NiceGUI 3.8: classic-script + es-module-shims loading paths for old browsers (Chrome 56+, Firefox 52+, iOS 12 Safari)

Project description

nicegui-legacy-browser

Legacy browser support for NiceGUI 3.8.x — an ASGI middleware (polyfills, JS transpilation/bundling, CSS transforms) that makes NiceGUI run on old browsers via two auto-selected loading paths. Verified floor: Chrome 56+, Firefox 52+, iOS 12 Safari (see the status note below for what's tested vs. aspirational).

Status (2026-07): two loading paths, auto-selected by the browser's User-Agent.

  • Native-ES-module browsers (Safari 12+, Chrome 61+, modern) → the es-module-shims path (validated incl. real iOS 12 Safari).
  • No-native-module browsers (Chrome 55–60, Firefox <60, Chromecast) → a classic-script bundle — verified mounting + interactive on Chromium 56, Firefox 52, and real iOS 12 Safari.

The floor is Chrome ~55/56, not 49 (the bundler can't lower syntax further without an added Babel pass), so Chrome 49 / Chromecast-1st-gen is not verified — treat those rows below as aspirational. Lazy-loaded components now load on the classic path via prebuilt per-component bundles (static/_classic/components/): leaflet is verified mounting on Chromium 56 (both eager and on-demand). aggrid/echart/plotly/mermaid build clean the same way but are deferred (browser-unverified, 1.5–7 MB) — uncomment a line in build_classic.sh to ship one. See FINDINGS.md and issue #2 for the per-component table.

Why?

NiceGUI 3.8.0 uses modern web features that break in old browsers:

Feature Required by Minimum Browser
<script type="importmap"> Vue loading Chrome 89, Safari 16.4
<script type="module"> Vue/component loading Chrome 61, Safari 11
CSS @layer Style ordering Chrome 99, Safari 15.4
Optional chaining ?. nicegui.js, Vue 3, components Chrome 80, Safari 13.1
Nullish coalescing ?? nicegui.js Chrome 80, Safari 13.1
globalThis Vue setup Chrome 71, Safari 12.1
async/await Event handling Chrome 55, Safari 10.1
Object.entries() nicegui.js Chrome 54
String.replaceAll() nicegui.js Chrome 85, Safari 13.1

This package bridges the gap by:

  1. Transpiling all JS (Vue 3, Quasar, nicegui.js, components) via Babel to remove modern syntax
  2. Polyfilling missing APIs (globalThis, Object.entries, replaceAll, etc.)
  3. Shimming ES modules and import maps via es-module-shims
  4. Transforming CSS to remove @layer, logical properties, revert-layer, etc.

Hard Requirements

Vue 3's reactivity system requires native Proxy support. This cannot be polyfilled. Therefore:

  • Chrome 49+ ✅ (Proxy added in Chrome 49)
  • Safari 10+ / iOS 10+
  • IE 11 ❌ (No Proxy — fundamentally impossible)

Quick Start

pip install nicegui-legacy-browser     # pulls in a compatible nicegui
from nicegui import ui
from nicegui_legacy_browser import enable

enable()  # call BEFORE ui.run()

@ui.page('/')
def index():
    ui.label('Works in old browsers!')

ui.run()

That's it — no build step. The transpiled/bundled JS ships prebuilt inside the package, so there is no Node.js requirement at install or runtime. enable() picks the right loading path per browser automatically (see below). You only need the nicegui-legacy-build command (and Node) to regenerate the bundles after bumping NiceGUI — see Regenerating the bundles.

How It Works

Architecture

Browser Request
    │
    ▼
┌─────────────────────────────┐
│  LegacyBrowserMiddleware    │  ASGI middleware wrapping NiceGUI
│  (intercepts all responses) │
├─────────────────────────────┤
│  HTML Transform:            │
│  • Inject polyfills.js      │  ← globalThis, Object.entries, replaceAll, ...
│  • Inject es-module-shims   │  ← Polyfills import maps for old browsers
│  • importmap → importmap-shim
│  • module → module-shim     │
│  • Strip CSS @layer         │
│  • Remove modulepreload     │
│  • Remove Tailwind v4 syntax│
├─────────────────────────────┤
│  JS Transform:              │
│  • Serve Babel-transpiled   │  ← ?. → null checks, ?? → ternaries,
│    versions of all .js      │     async/await → generators
├─────────────────────────────┤
│  CSS Transform:             │
│  • Strip @layer             │
│  • revert-layer → revert    │
│  • Logical props → physical │  ← margin-block-start → margin-top
│  • Remove :dir()            │
└─────────────────────────────┘
    │
    ▼
  NiceGUI App (unmodified)

Prebuilt bundles (no build needed to use)

The lowered JS ships committed inside the package — both the static/_transpiled/ files (Babel-transpiled originals, for the es-module-shims path) and the static/_classic/ bundles (esbuild classic-script bundles, for no-native-module browsers). Installing the package is enough; enable() serves them directly. Node.js is not a dependency of normal use — it lives behind the optional [build] extra and is only needed to regenerate the bundles (below).

No Hooks Required in NiceGUI

This package uses standard ASGI middleware via app.add_middleware(). No modifications to NiceGUI's source code are needed. The middleware:

  1. Intercepts HTML responses to inject polyfills and transform inline CSS
  2. Intercepts JS responses to serve transpiled versions
  3. Intercepts CSS responses to strip @layer and transform logical properties
  4. Serves its own static files (polyfills.js, es-module-shims.js)

Browser Compatibility Matrix

Browser Version Status Notes
Chrome 49-54 ⚠️ Unverified Below the classic-bundle floor (~55/56); needs a Babel pass — see issue #3
Chrome 55-60 ✅ Works Classic-script bundle (verified on Chromium 56)
Chrome 61-79 ✅ Works Import maps shimmed
Chrome 80-88 ✅ Works Import maps shimmed
Chrome 89+ ✅ Works Native import maps
Safari 12 (iOS 12) ✅ Works Import maps shimmed
Safari 13-13.1 ✅ Works Import maps shimmed
Safari 14-16.3 ✅ Works Import maps shimmed
Safari 16.4+ ✅ Works Native import maps
Chromecast 1st gen ~Chrome 49-55 ⚠️ Unverified Aspirational; ~Chrome 49 is below the classic floor — see issue #3
IE 11 ❌ Impossible No Proxy support

Configuration

enable(
    transpiled_dir=None,           # Path to pre-transpiled JS (auto-detected)
    legacy_static_prefix='/_nicegui_legacy',  # URL prefix for polyfill files
    auto_build=True,               # Auto-run build if transpiled files missing
    target='default',              # Browser target: chrome49, chrome55, safari12, default
)

Build Targets

Target Transforms Use Case
default Everything (chrome 49 + safari 12) Maximum compatibility
chrome49 async/await + all ES2020+ Chromecast 1st gen
chrome55 ES2020+ only (keeps async/await) Chromecast 2nd gen
chrome61 ES2020+ only (keeps modules) Older desktops
safari12 ES2020+ only iOS 12 devices

Known Limitations

  1. Tailwind CSS v4: Not supported in old browsers. The JIT compiler requires Chrome 111+. Use Tailwind v3 or UnoCSS with a compatible preset instead.

  2. Mermaid diagrams: Some mermaid dist files (3 out of ~40) fail Babel transpilation due to complex generator patterns. The originals are used as fallback — they may not work in Chrome < 55.

  3. WebGL (3D scenes): ui.scene() requires WebGL which has varying support on old hardware. Chromecast 1st gen does not support WebGL.

  4. CSS gap in flexbox: Not supported in Chrome < 84. Some spacing may be slightly off. This is a cosmetic issue only.

  5. Performance: The middleware adds ~1ms of overhead per HTML response for the transform. JS/CSS transforms add negligible overhead due to caching.

  6. File size: Polyfills add ~64KB (es-module-shims) + ~12KB (polyfills.js) to the initial page load.

Testing with Old Browsers

On x86_64 Linux (with Docker)

# Download old Chromium snapshot for testing
# Chrome 55 (last without async/await native support)
docker run -d -p 4444:4444 selenium/standalone-chrome:3.141.59

# Or download a Chromium binary directly:
# 1. Find revision: https://omahaproxy.appspot.com (version 55.0.2883.87 → revision ~433059)
# 2. Download: https://commondatastorage.googleapis.com/chromium-browser-snapshots/Linux_x64/433059/chrome-linux.zip

On macOS

Use Safari's Responsive Design Mode or install old Safari versions via Xcode.

On actual devices

For Chromecast testing:

pip install catt
catt cast_site http://your-server:8080/

Development

git clone <repo>
cd nicegui-legacy-browser
pip install -e ".[test]"    # bundles are committed; no build needed to run tests
pytest tests/ -v

To regenerate the bundles after a NiceGUI bump, see Regenerating the bundles (adds the [build] extra + Node).

Version Compatibility

Pinned to nicegui>=3.7,<3.9. The shipped bundles (static/_transpiled/, static/_classic/) are lowered copies of a specific NiceGUI release's static assets, so they are coupled to that release's JS. A NiceGUI bump can reshape that markup — the classic transform will fail loudly if it no longer recognises the page (rather than silently serving a broken page), signalling a regenerate is due.

Regenerating the bundles

Only needed after bumping NiceGUI (or to add a lazy component). Requires Node.js, pulled in via the optional [build] extra:

pip install -e ".[build]"
nicegui-legacy-build --target default                 # es-module-shims path (Babel)
bash nicegui_legacy_browser/build/build_classic.sh    # classic-bundle path (esbuild)

Commit the regenerated static/_transpiled/ + static/_classic/ so users still get a build-free install.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nicegui_legacy_browser-0.1.1.tar.gz (7.1 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nicegui_legacy_browser-0.1.1-py3-none-any.whl (7.3 MB view details)

Uploaded Python 3

File details

Details for the file nicegui_legacy_browser-0.1.1.tar.gz.

File metadata

  • Download URL: nicegui_legacy_browser-0.1.1.tar.gz
  • Upload date:
  • Size: 7.1 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.11

File hashes

Hashes for nicegui_legacy_browser-0.1.1.tar.gz
Algorithm Hash digest
SHA256 2a069b7e7d4613690c80fc6d94db78a6fe604aa66b9889d6bf546a6fe46090f7
MD5 c3bf068c8728d0e374725f01fdc32937
BLAKE2b-256 5de6278b2526cee380fe5b6795d6687e4d90ac3f002686df177023b3f509b53c

See more details on using hashes here.

File details

Details for the file nicegui_legacy_browser-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for nicegui_legacy_browser-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 598ee5915f6ef80decc82fcea995298abe4af5307fd0841105b12d6180e687fe
MD5 9930460945cdbc215f1c4a7fddf8e2d7
BLAKE2b-256 71504af67db6add228ee05bb954a35071a04bbe490498aceb905337aaf3b5bbe

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page