Skip to content

fix(examples): mount www/ in Core-mode apps - #210

Merged
schloerke merged 1 commit into
schloerke/example1-oldfaithful-hellofrom
schloerke/core-static-assets
Aug 19, 2026
Merged

fix(examples): mount www/ in Core-mode apps#210
schloerke merged 1 commit into
schloerke/example1-oldfaithful-hellofrom
schloerke/core-static-assets

Conversation

@schloerke

@schloerke schloerke commented Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Stacked on #207 (base schloerke/example1-oldfaithful-hello). Split out of that PR to keep the two ideas separate: #207 rewrites the 01-hello example, this fixes a real bug it happened to surface.

The bug

page_react_html() reads index.html but does not serve the files index.html references. Shiny Express mounts the app directory's www/ at / automatically:

# shiny/express/_run.py
www_dir = file.parent / "www"
if www_dir.is_dir():
    app_opts["static_assets"] = {"/": www_dir}

Core's App() has no equivalent — static_assets defaults to None. So every Core app in this repo served / fine and then 404'd on its own scripts and stylesheets.

This is not a path-resolution issue (page_react_html() found index.html correctly all along), which is why it presented as "the page loads but nothing renders."

What was broken

Both Core-mode examples, and only those:

  • examples/01-hello/app-core.py — 404 on /app.js and /main.css.
  • examples/10-bookmarking/app.py — same cause, worse symptom: its entire client bundle 404'd, so it rendered a completely blank page.

Both now pass static_assets={"/": Path(__file__).parent / "www"}.

I swept all ten examples to confirm the blast radius. Eight are Express (set_react_page()) and unaffected. The remaining 404s are unrelated and expected: 03-columns-shadcn / 04-shadcn need npm run build (their bundles are gitignored) and 09-hmr gets www/app.js from the Vite dev server. Proof those are not this bug: www/index.html lives inside the mounted directory, and curl /index.html returns 200 on both — the mount is live, the bundles just aren't built.

Docs

The trap is invisible until you run the app, so it's documented where a Core user will actually meet it:

  • a "Serving the client's files" section in page_react_html()'s docstring, with the working snippet
  • the Core snippet in pkg-py/README.md, which previously showed App(page_react_html(...), server) — i.e. the broken form

R needs no counterpart: shiny::runApp() serves www/ next to app.R automatically. That is exactly why 01-hello's app.R worked all along and masked the Python-side gap.

Tests

None added — this is docs-and-examples only, with no package behavior change (page_react_html() is untouched apart from its docstring), so there is nothing new to assert.

Worth considering as follow-ups, happy to file either:

  1. A CI smoke test over examples/ — boot each app, assert / and every src/href in its index.html returns 200. This is how 10-bookmarking's blank page would have been caught instead of sitting broken.
  2. A warning from page_react_html() when the resolved index.html's directory isn't among the app's static mounts. That is a real behavior change and would need its own tests.

Verification

  • app-core.py: /, /app.js, /main.css all 200, and the full slider → histogram round trip drives correctly in a browser.
  • 10-bookmarking: renders again, and bookmark restore still hydrates — ?_inputs_&txt="hi"&num=7 populates the inputs and the server echoes text='hi' num=7.
  • Console clean apart from favicon.ico.
  • make py-check-tests (74 passed), make py-check-types clean, ruff clean.

Stack created with GitHub Stacks CLIGive Feedback 💬

page_react_html() reads index.html but does not serve the files index.html
references. Shiny Express mounts the app directory's www/ at "/"
automatically (shiny/express/_run.py); Core's App() leaves static_assets
None, so the page loaded and then 404'd on its own app.js and main.css.

Both Core examples were affected — 01-hello/app-core.py and, less visibly,
10-bookmarking/app.py, which rendered a blank page because its entire client
bundle 404'd. Both now pass static_assets={"/": <app dir>/www}.

Documents the requirement where a Core user will actually meet it: a
"Serving the client's files" section in page_react_html()'s docstring and the
Core snippet in pkg-py/README.md. R needs no counterpart — shiny::runApp()
serves www/ next to app.R automatically.

Docs-and-examples only; no package behavior change, so no new tests.
@schloerke
schloerke merged commit 3c8420f into main Aug 19, 2026
8 checks passed
@schloerke
schloerke deleted the schloerke/core-static-assets branch August 19, 2026 21:06
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.

1 participant