Web
The same app runs in the browser as a single page app. Your Python runs on Pyodide in the page, so there is no server to host: any static host works.
Run and build
pyxpo run web # dev server on http://127.0.0.1:8000/, reloads on save
pyxpo build web # static site in build/web/The dev server reloads the page when a file in app/, assets/ or pyproject.toml changes. Options: --port, --no-open, --base /myapp and --no-devtools. See the CLI reference.
How it works
- The app's Python runs in the browser on Pyodide.
- The pyxpo reconciler is the virtual DOM. It diffs component trees with keyed children and moves only the nodes that left their order.
app.jsapplies the resulting ops to real DOM nodes. - The router keeps the address bar, the page title and browser history in step. Links, back and forward, refresh and deep links work as on any site.
It feels like a web site
Stackswaps pages at once, with no slide and no edge swipe. Pages below the top stay mounted, so Back restores their scroll position, state and keyboard focus.Linkrenders a real anchor. Ctrl/Cmd-click, middle-click and "Copy link" work.- Pressables show a hover state, can be reached with Tab and pressed with Enter or Space.
router.runtime.on_web()tells your code it runs in a browser.
Config
[tool.pyxpo.web]
base = "/myapp" # the site lives under this path (default: the site root)
title = "My App" # page title (default: the app name)
packages = ["numpy"] # extra packages the browser installs with micropip[tool.pyxpo] requires are installed with micropip too, so they must be pure Python or built for Pyodide.
Deploy
Upload build/web/ to any static host: GitHub Pages, Netlify, Vercel, Cloudflare Pages, S3. The host must serve index.html for unknown paths. The build also writes a 404.html for hosts such as GitHub Pages. Set base when the site is not at the domain root.
Native modules on the web
A module works on the web when its package has a web.py backend with call(method, args), which may return an awaitable. The official image modules have one:
| Module | On the web |
|---|---|
image-picker | Opens the browser's file chooser. No camera. |
image-manipulator | Runs Pillow in the browser. |
media-library | Saving an image downloads the file. |
sharing | Uses the Web Share API, or downloads the files when the browser has none. |
Helpers for your own backends are in pyxpo.renderers.web.browser: choose_files, save_file and download.
Dev tools
pyxpo run web shows a round button at the bottom right of the page. It opens a panel for building responsive UI without an emulator. pyxpo build web never includes it.
- View: Desktop, Mobile, Tablet or Custom. Mobile and Tablet show the app in a device body (iPhone 15 Pro, iPhone SE, Pixel 8, iPad, Galaxy Tab and more) with its status bar, notch or home indicator and safe area insets. Custom takes any width and height, or drag the frame edges.
- In a device the screen behaves like a touch screen: no hover, a round touch cursor, drag to scroll with momentum. The app gets the device size, pixel ratio and insets, so
useWindowDimensions,SafeAreaViewand breakpoints react as on the phone. - Breakpoint: the active breakpoint and window size. Click a breakpoint to view the app at that width.
- Appearance: System, Light or Dark, to check your themes.
- Behaviour: Web, iOS or Android sets
Platform.OS, so stacks slide and swipe like the phone app. On Android, Esc is the back button. - A toolbar next to the device works like an emulator's: rotate, zoom, fit, 1:1, light / dark, back and reload. Zoom goes from 20 to 300%, also with Ctrl/Cmd + scroll or a trackpad pinch. Cmd/Ctrl+Shift+M turns the device view on and off.