Skip to content

fix(web): make the client Flet actually serves visible and overridable - #6835

Merged
FeodorFitsner merged 8 commits into
mainfrom
fix/web-path-built-client
Sep 14, 2026
Merged

FeodorFitsner merged 8 commits into
mainfrom
fix/web-path-built-client

Conversation

@ndonkoHenri

@ndonkoHenri ndonkoHenri commented Sep 11, 2026 •

Copy link
Copy Markdown
Contributor

Four related fixes that came out of chasing why a third-party extension renders as Unknown control in the browser but works on desktop.

1. FLET_WEB_PATH now works with a flet build web output

flet run --web, ft.run(export_asgi_app=True) and flet publish serve the prebuilt web client from the flet-web package. Its extension list is fixed when Flet is released, so a third-party control renders as Unknown control: <Type> there however the app was built — the reason extensions work on desktop (where flet run prefers a client from a previous flet build) and vanish on web.

FLET_WEB_PATH already pointed the server at another web root, but aiming it at a built app did not work: that page bakes flet.pyodide = true into its config and shipped no <!-- fletAppConfig --> marker, so the server could inject nothing and the client kept trying to start Python in the browser.

The build template now carries the marker, and patch_index_html writes the Pyodide flag either way instead of relying on the page's own default.

Verified: flet build web on an app using a third-party extension, then FLET_WEB_PATH=build/web flet run --web — the extension renders, host Python over the socket, no Pyodide worker. Both existing paths are unchanged (prebuilt client served with the flag off, flet publish with it on).

Deliberately not included: auto-detecting ./build/web the way desktop auto-detects build/<platform>. On web that would silently reinterpret a Pyodide artifact as a server-mode client, and the same directory is separately runnable via flet serve — so someone could reasonably believe flet run --web is testing what they would deploy. Worth proposing on its own.

2. flet run -v enables logging

-v was accepted and advertised as "enable verbose output", but run.py never read options.verbose and nothing mapped it to a log level. flet run --web -v printed nothing at all, leaving every logger.info in the web transport unreachable.

flet run now configures logging for its own process and passes the level to the app it starts through a new FLET_LOG_LEVEL (-v info, -vv debug). Both halves are needed: the app runs in a subprocess, but the desktop client is launched from the CLI process.

basicConfig is a no-op once the root logger has a handler, so an app that configures logging keeps what it chose.

lines debug web root
no flag 0 (unchanged) 0 —
-v 19 0 shown
-vv 86 67 shown
-v, app sets ERROR 6 0 — (app wins)

3. macOS no longer crashes on a stale FLET_VIEW_PATH

The path went straight into os.listdir, so a stale or emptied developer client raised a bare FileNotFoundError from a daemon thread — surfacing as Exception in thread Thread-4 (open_flet_view_and_wait) and ending the run. Windows and Linux already check and warn, then fall through to the cached client. macOS now does the same through a shared find_macos_app_bundle, which also replaces the hand-rolled scan of build/macos.

The web root also names FLET_WEB_PATH when that is where it came from, matching what desktop reports for FLET_VIEW_PATH.

4. Both variables are documented

FLET_VIEW_PATH and FLET_WEB_PATH appeared nowhere in the docs. Added to the environment variables reference with FLET_VIEW_PATH's resolution order spelled out — flet build output, then the variable, then the cached client — since which client actually runs is otherwise guesswork. FLET_LOG_LEVEL added too, plus a note in the logging cookbook that flet run -v sets it, which lets someone produce logs for an issue report without editing their app.

Summary by Sourcery

Make web client selection overridable, expose useful verbose logging, and harden desktop client discovery.

New Features:

  • Enable serving prebuilt web clients through FLET_WEB_PATH, including clients containing third-party extensions.
  • Add verbose logging support to flet run, with INFO and DEBUG levels propagated to the launched app through FLET_LOG_LEVEL.

Bug Fixes:

  • Prevent macOS runs from crashing when FLET_VIEW_PATH is missing or no longer contains a client bundle.
  • Ensure served web clients receive the correct runtime mode and app package configuration.

Enhancements:

  • Improve desktop and web client source diagnostics and document client path resolution behavior.

Documentation:

  • Document FLET_LOG_LEVEL, FLET_VIEW_PATH, and FLET_WEB_PATH, and explain how flet run verbosity configures application logging.

Tests:

  • Add coverage for web client base-path patching and application logging configuration.

`flet run --web`, `ft.run(export_asgi_app=True)` and `flet publish` all serve the
prebuilt web client from the `flet-web` package. Its extension list is fixed when
Flet is released, so a third-party control renders as `Unknown control: <Type>`
in those modes no matter how the app was built — the reason extensions appear to
work on desktop (where `flet run` prefers a client from a previous `flet build`)
and vanish in the browser.

`FLET_WEB_PATH` already pointed the server at a different web root, but aiming it
at a `flet build web` output did not work: that page bakes `flet.pyodide = true`
into its config literal and shipped no `<!-- fletAppConfig -->` marker, so the
server could inject nothing and the client kept trying to start Python in the
browser instead of connecting over the socket.

The build template now carries the marker, and `patch_index_html` writes the
Pyodide flag either way rather than relying on the page's own default. A client
generated for one mode can therefore be served in the other.

Verified end to end: `flet build web` on an app using a third-party extension,
then `FLET_WEB_PATH=build/web flet run --web` — the extension control renders,
with host Python over the socket and no Pyodide worker. Both existing paths are
unchanged: the prebuilt client is still served with the flag off, `flet publish`
still with it on.
Both point Flet at a client you supply instead of the one it downloads or
bundles, and neither appeared anywhere in the docs.

`FLET_WEB_PATH` is the one worth finding: pointing it at a `flet build web`
output is how a third-party extension renders in `flet run --web`, since
extension Dart code is compiled into the client and the bundled one is built
when Flet is released.

`FLET_VIEW_PATH` gets its resolution order spelled out — `flet build` output,
then this variable, then the cached client — because which client actually runs
is otherwise guesswork.

[skip ci]
`-v` was accepted and advertised as "enable verbose output", but `run.py` never
read `options.verbose` — nothing anywhere mapped the flag to a log level. So
`flet run --web -v` printed nothing, and the 26 `logger.info`/`logger.debug`
calls in the web transport were unreachable unless the app configured logging
itself.

`flet run` now passes the level to the app it starts through `FLET_LOG_LEVEL`
(`-v` info, `-vv` debug), and `ft.run()` applies it. `basicConfig` is a no-op
once the root logger has a handler, so an app that sets up logging keeps what it
chose.

The web root also names `FLET_WEB_PATH` when that is where it came from. The
desktop client already reports this for `FLET_VIEW_PATH`, and without it the
line gives a path with no indication of which source won.

Measured on a web app: no flag 0 lines (unchanged), `-v` 19 lines, `-vv` 86
lines of which 67 debug, and an app calling `basicConfig(level=ERROR)` still
prints neither.
… bundle

On macOS the variable was trusted without checking: the path went straight into
`os.listdir`, so a stale or emptied developer client produced a bare
`FileNotFoundError` from a daemon thread — surfacing as
"Exception in thread Thread-4 (open_flet_view_and_wait)" and ending the run.
Windows and Linux already check their executable and warn, then fall through to
the cached client; macOS now does the same through a shared
`find_macos_app_bundle` helper, which also replaces the hand-rolled scan of
`build/macos`.

`flet run` also configures logging for its own process, not only for the app it
starts. `FLET_LOG_LEVEL` reaches the child, but the desktop client is launched
from the CLI process, so with `-v` the app talked while the launcher stayed
silent about which client it picked — the one thing worth knowing when the
wrong one loads.

Verified on macOS: FLET_VIEW_PATH at an empty directory now logs
"FLET_VIEW_PATH set to ... but no .app bundle found there" and moves on, and a
valid one logs the bundle it took and starts the session.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

@ndonkoHenri
ndonkoHenri requested review from FeodorFitsner and a lite review from Copilot September 11, 2026 16:31
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Sep 11, 2026 •

Copy link
Copy Markdown

Deploying flet-website-v2 with  Cloudflare Pages  Cloudflare Pages

Latest commit: b8cf74a
Status: ✅  Deploy successful!
Preview URL: https://ae18256a.flet-website-v2.pages.dev
Branch Preview URL: https://fix-web-path-built-client.flet-website-v2.pages.dev

View logs

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Three unresolved moderate findings remain concerning relative FLET_WEB_PATH resolution and stale published app archive URLs.

Once you've addressed the issues Copilot identified, you can request another Copilot review.

Pull request overview

Updates Flet’s web-client selection, logging, macOS fallback behavior, and related documentation.

Changes:

  • Supports built web clients through FLET_WEB_PATH with explicit Pyodide configuration.
  • Enables -v/-vv logging and propagates FLET_LOG_LEVEL.
  • Improves macOS client fallback handling and documents the new environment variables.
File summaries
File Reviewed changes
website/docs/reference/environment-variables.md Documents client-path and logging environment variables.
website/docs/cookbook/logging.md Documents verbose run logging.
sdk/python/templates/build/{{cookiecutter.out_dir}}/web/index.html Adds the runtime configuration marker.
sdk/python/packages/flet/src/flet/app.py Applies FLET_LOG_LEVEL.
sdk/python/packages/flet-web/src/flet_web/patch_index.py Configures Pyodide mode. Moderate, 2 votes: published pages may retain a stale app archive URL.
sdk/python/packages/flet-web/src/flet_web/fastapi/flet_static_files.py Handles custom web-root selection. Moderate, 2 votes: relative FLET_WEB_PATH resolves from the child process directory.
sdk/python/packages/flet-desktop/src/flet_desktop/__init__.py Safely handles missing macOS client bundles.
sdk/python/packages/flet-cli/src/flet_cli/commands/run.py Configures and propagates verbose logging. Moderate, 1 vote: relative FLET_WEB_PATH fails after changing the child working directory.
CHANGELOG.md Records the user-facing fixes.
Review details

Suppressed comments (1)

sdk/python/packages/flet-cli/src/flet_cli/commands/run.py:467

  • Handler.start_process() launches the child with cwd=self.flet_app_data_dir, but this inherited FLET_WEB_PATH is passed through unchanged. Therefore the documented/claimed command FLET_WEB_PATH=build/web flet run --web resolves relative to .flet/storage/data and fails to find the project’s build/web; resolve relative web paths before spawning (or explicitly require an absolute path).
        if self.verbose > 0:
            p_env["FLET_LOG_LEVEL"] = "debug" if self.verbose > 1 else "info"
  • Files reviewed: 9/9 changed files
  • Comments generated: 2
  • Review effort level: Lite

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread sdk/python/packages/flet-web/src/flet_web/patch_index.py
ndonkoHenri and others added 2 commits September 11, 2026 19:35
…URL current

Two problems with pointing FLET_WEB_PATH at a `flet build web` output, both
raised by Copilot on #6835.

`flet run` starts the app with its cwd set to the storage directory, so
`FLET_WEB_PATH=build/web` — the form the docs give — resolved under storage and
failed with "Web root path not found". The path is now resolved before the child
is spawned, while the directory the user typed it from is still the meaning.

`flet publish` writes the app as `app.tar.gz`, but a built page names the archive
it was generated with, `assets/app/app.zip`. Publishing through such a client
therefore pointed the page at the stale build archive. `patch_index_html` now
writes the archive URL for the caller that knows it, alongside the Pyodide flag
it already states explicitly.

Verified: `FLET_WEB_PATH=build/web flet run --web` serves the built client; a
built page patched for publish reports `app.tar.gz` while the prebuilt client is
unaffected, and neither URL is injected in server mode, where it means nothing.
@FeodorFitsner
FeodorFitsner merged commit 2bdde56 into main Sep 14, 2026
51 of 92 checks passed
@FeodorFitsner
FeodorFitsner deleted the fix/web-path-built-client branch September 14, 2026 19:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants