` and all markup arrives over the websocket, so `curl` and search engines see
+ nothing. Only `html_head` and `prepend_body` are server-rendered.
+- `html_head` **must** be built with `html.head(...)` → otherwise, at request time (500, not
+ import time): ``ValueError: Head element must be constructed with `html.head`.``
+- `prepend_body` defaults to `html.noscript("Enable JavaScript to view this site.")`; it is
+ rendered with `reactpy_to_string`, so it may not use hooks.
+- `@my_app.route(path, type="http"|"websocket")` and `my_app.lifespan(app)` add your own routes
+ (path is a regex, `^`/`$` auto-added; the app may be a callable or a dotted-path string).
+- `pyscript_setup=True` loads PyScript alongside server-rendered components for mixed setups.
+- Serves `{path_prefix}` (index + dispatcher), `{path_prefix}static/` (client bundle),
+ `{path_prefix}modules/` (web modules). Everything else is yours.
+
+**`ReactPyMiddleware(app, root_components, **settings)`**
+- `root_components` is a required iterable of **dotted paths** (`["main.counter"]`), resolved via
+ the Python import system from the server's working directory. Failures at construction:
+ `ImportError: ReactPy failed to import "main"` / `AttributeError: ReactPy failed to import
+ "counter" from "main"`; no dot at all → `ValueError`.
+- It **never serves HTML**: registering a component does not create a page. Emit the mount
+ markup yourself with `server_side_component_html(element_id="app", class_="",
+ component_path="main.counter/")` — **the trailing slash is required** (the websocket route is
+ `^{path_prefix}(?P
[a-zA-Z0-9_.]+)/$`). Without it: `Unexpected response code` +
+ `[ReactPy] Failed to connect!` and an empty div.
+- Mounting by hand (`Loading...