PyWeb 0.4.0
Apps that are bigger, livelier and smarter: npm packages without
Node.js, multi-page apps with layouts and client-side navigation,
streaming for AI features, and page data that follows the database.
Added
- npm packages without Node.js.
pyweb add chart.js/autodownloads a
package from the npm registry, checks its sha512 checksum, follows its
imports from the browser entry point and copies only the files it
needs (and its dependencies) intostatic/vendor/, pinning versions in
pyweb.lock.pyweb addwith no arguments reinstalls from the lock;
pyweb removetakes a package out. Browser code binds exports with
Chart = npm("chart.js/auto")ornpm("pkg", "Export"). Calling a
class constructs it and keyword arguments become an options object.
Each page imports only the packages it uses, through an import map
that the Content Security Policy allows by hash. CommonJS-only and
Node.js-only packages are refused with an explanation, and an
uninstalled package is a compile error that names the command to run. ref={el}sets a page variable to an element, in time for
on_mount, for libraries that draw into the page.- Changing an attribute of a package's object (
chart.value = 5)
re-renders whatever shows it. - Web components (custom elements from npm) work in markup.
pyweb lsp: hover shows an npm binding's installed version and
TypeScript signature; completion offers installed packages in
npm("and a module's exports aftername..- New docs page: npm packages.
- Layouts.
@app.layoutwraps every page (or, with
@app.layout("/admin"), pages under a prefix) in shared markup;
{children}marks where the page goes. Layouts nest, have their own
server code, state and handlers, and pages can opt out with
layout=Noneor pick one withlayout="Name". - Client-side navigation. Links between pages fetch the next page's
HTML and swap it in below the layouts both pages share, so layout
state (an open menu, a player) survives. Links are prefetched on
hover or focus, back/forward restore the scroll position, and anything
unusual falls back to a full page load.navigate("/path")from
pyweb.browserdoes the same from browser code;on_unmountruns
when a page is left;App(client_nav=False)turns it off. - Current links. Links to the current page get
aria-current="page"and links to its parent sections
aria-current="true", on the server and after each navigation. - Head tags.
@app.page(description=..., image=..., noindex=...)and
head(title=..., description=...)in page code add description, Open
Graph and Twitter tags;App(base_url=...)adds canonical URLs and
absolute image links. - Error pages in
.pyweb.@app.error(404)/@app.error(500)pages
takepath,status,messageorrequest_idand use root layouts. - Typed query parameters. Page parameters that aren't in the route
are read from the query string and converted by annotation (int,
float,bool,list[...]); bad or missing values answer 400. - New docs page: Layouts & navigation.
- Streaming server functions. A
@serverfunction thatyields
sends each value as it's produced (NDJSON over the same RPC endpoint);
browser code reads it withasync for.stream.cancel()or leaving the
loop aborts the request and closes the generator on the server, so an
upstream AI call stops too. Errors raised part-way arrive as
RPCError. Works withasync defgenerators, underpyweb serve,
pyweb devand ASGI, andTestClient.rpcreturns the streamed values. <Markdown text={...} />(frompyweb) renders Markdown to safe
HTML on the server and updates it in the browser as the text changes,
with the same rules in both places. Raw HTML is shown as text and
links only accept http(s), mailto and relative URLs.ai-chattemplate and example: a streaming chat with Stop and
Markdown replies that talks to Anthropic, any OpenAI-compatible server
(OpenAI, Ollama, vLLM, ...) or a built-in demo model, chosen by
environment variables.pyweb new NAME --template ai-chat.- New docs page: Building AI apps.
- Live data.
rows = live(db, "select ...", params)in a page or
layout renders the rows and keeps them current: writes through
pyweb.db(andpyweb.models) announce their table after commit, each
distinct query re-runs once per change (bursts coalesced) and sends
rows to every page showing it only when they changed. Pages follow a
signed feed;db.notify("table")covers writes made elsewhere. With
RedisBusit works across processes, and any process can take over a
query from the page's signed description. - New docs page: Live data.
watch(lambda: value, handler)(frompyweb.browser) runs a
handler whenever a value changes, for work outside markup such as
redrawing a chart or saving a draft.pyweb addapplies packages'browserfield (browser versions of
files, modules turned off), so packages such as ethers install.- New examples: dashboard (live queries and a Chart.js chart from
npm), site (layouts, navigation, query parameters, a 404 page) and
ai-chat. The playground has the site and AI chat examples. - New docs page: Recipe: wallets & web3 (wallet sign-in with ethers and
eth-account). - A layout's
{children}can sit on a line of its own.
Fixed
- Subscriptions and cleanups set up in
on_mountnow end when the page
is left (they were never stopped).
Changed
- The experimental
pyweb.livemodule (in-memory live tables) is now
pyweb.livetable;pyweb.liveis the new live-query function. pyweb.npm(TypeScript declarations to dataclasses) is now
pyweb.dts, and its command ispyweb dts.pyweb buildno longer
writes an esm.sh import map; packages come frompyweb.lock.- The default Content Security Policy adds
worker-src 'self' blob:so
packages can start Web Workers. - The starter stylesheet styles Markdown and chat bubbles.
- The browser runtime is about 14 KB gzipped (was about 11 KB), for
client-side navigation and npm support. - New website design: a colour system where blue means the browser and
amber the server, self-hosted Inter / Bricolage Grotesque / JetBrains
Mono, dark code windows, and a landing page that shows each line of an
app with where it runs (worked out by the compiler) next to the real
compiled output. - The example apps and the
pyweb newstylesheet use the new palette.