The website and the in-browser build
The site at xpsflow.pages.dev is a static build: a landing page, these docs, and the
workbench running entirely in the browser. Nothing on it talks to a server.
How the browser build works
scripts/build_site.py assembles dist/:
| path | what it is |
|---|---|
index.html, site.css, site.js |
the landing page |
docs/*.html and docs/*.md |
each documentation page, with its Markdown twin linked as rel="alternate" |
app/ |
the workbench front end from src/xpsflow/web/static, re-pointed at a Web Worker |
app/worker.js |
loads Pyodide, installs the wheels and runs xpsflow.web.browser.BrowserApp |
app/browser-backend.js |
patches fetch and window.open so every /api/... call goes to the worker |
app/pyodide/ |
the pinned Pyodide runtime and the wheels it needs, resolved from its lock file |
app/wheels/ |
the pure-Python wheels not in Pyodide (lmfit, asteval, dill) and the xpsflow wheel |
_headers, _redirects, robots.txt, sitemap.xml, llms.txt, .well-known/security.txt |
hosting and discovery files |
BrowserApp mirrors the FastAPI endpoints over one Session, so the same JavaScript runs
against either backend. The first visit downloads about 25 MB (cached afterwards); fits run at
roughly a third of native speed. PDF export and the tool-calling assistant need the local
install, because WeasyPrint has no WebAssembly build and the assistant needs a model endpoint.
Building and previewing
python scripts/build_site.py --out dist --no-runtime # pages only, fast
python scripts/build_site.py --out dist # with the runtime
python -m http.server --directory dist 8000
Deployment
.github/workflows/deploy.yml builds the site on every push to main that touches the
package, the docs or the site, and publishes it to Cloudflare Pages with
wrangler pages deploy. It needs two repository secrets: CLOUDFLARE_API_TOKEN (a token
with Cloudflare Pages: Edit) and CLOUDFLARE_ACCOUNT_ID. A manual deploy from a machine with
wrangler logged in is npx wrangler pages deploy dist --project-name=xpsflow.
Headers
The _headers file sets a Content Security Policy with 'wasm-unsafe-eval' (required for
WebAssembly), restricts workers and connections to the site's own origin, denies framing, and
marks the runtime, wheels, fonts and vendor files as immutable so browsers cache them for a
year.