Skip to content

Force correct MIME types for UI assets on Windows (fixes unstyled UI) - #309

Open
zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-37-dennis
Open

zwanski-start wants to merge 1 commit into
AutoForgeAI:masterfrom
zwanski-start:swarm/issue-37-dennis

Conversation

@zwanski-start

Copy link
Copy Markdown

Closes #37

Problem

On Windows, Python's mimetypes module reads extension → type mappings from the registry (HKEY_CLASSES_ROOT). Third-party software often rewrites these, e.g. .css/.js → text/plain. Starlette's StaticFiles/FileResponse use mimetypes.guess_type, so the built UI gets served with the wrong Content-Type, and browsers then ignore the styles, scripts, SVGs or fonts.

The repo already had a fix, but it only covered .js and only ran as an import side effect of server/routers/settings.py. CSS, SVG and fonts were not covered.

Change

  • New server/utils/mime_types.py with register_static_mime_types(). It forces the correct types for every asset type the Vite build produces (.css, .js, .mjs, .svg, .json, .map, fonts, images, .wasm).
  • server/main.py calls it right before mounting /assets and the SPA fallback.
  • Removed the old .js-only hack from routers/settings.py.
  • New test_mime_types.py: fakes a corrupted registry (.css/.js → text/plain, .svg → application/octet-stream), then checks both guess_type and the headers an actual StaticFiles mount sends.

Verification

  • pytest test_mime_types.py test_ws_security.py → 13 passed; ruff check clean.
  • Started the real server on port 5247 and checked every asset referenced by ui/dist/index.html: .js → text/javascript, .css → text/css, /vite.svg → image/svg+xml.
  • In Playwright, the page loads with 2 stylesheets (322 rules) and --primary resolves.

Assumptions

  • I can't reproduce on Windows. The screenshot shows the layout rendering but colors and icons missing, from an older "AutoCoder" build. A wrong registry MIME mapping is the most common cause of "assets load but don't apply" for FastAPI on Windows, and this change hardens that path. If the reporter still sees it after updating, the next step is their browser's Network tab (Content-Type of index-*.css).

🤖 Generated with Claude Code

Windows registry mappings can make Python's mimetypes report .css/.js/.svg
as text/plain or similar, so StaticFiles serves the built UI with the wrong
Content-Type and browsers drop styles/scripts. Register the correct types
explicitly before mounting /assets, replacing the partial .js-only fix that
lived as an import side effect in routers/settings.py.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@zwanski-start

Copy link
Copy Markdown
Author

🔍 QA report: ✅ Passed

Tester: Ken (cubefarm agent, in a fresh session) · Round: 1 · Author: Dennis

The PR forces correct MIME types for every asset the UI build produces, and the server applies them before mounting the static assets. With a simulated broken Windows registry (.css/.js → text/plain, .svg → octet-stream), master serves the CSS as text/plain and vite.svg as application/octet-stream; with this PR they come back as text/css and image/svg+xml, and the page loads fully styled with no console errors. Lint, build and tests show no regressions: the pre-existing pytest and mypy failures are identical on master. Not tested on real Windows, so the fix is verified against the most likely cause of the issue, not the reporter's machine.

Check Details
✅ Issue repro: wrong Content-Type under corrupted mimetypes registry Faked broken registry entries (.css/.js → text/plain, .svg → application/octet-stream), imported server.main and requested the assets in-process over httpx ASGITransport from client 127.0.0.1. Master: index-*.css → text/plain, /vite.svg → application/octet-stream. PR: text/css, text/javascript, image/svg+xml.
✅ Real server with corrupted registry (PR) Ran uvicorn on 127.0.0.1:5345 with the corruption applied before startup. Every asset referenced by index.html, plus /vite.svg and /, returned 200 with the correct type (js → text/javascript, css → text/css, png → image/png, svg → image/svg+xml, html → text/html). /api/projects and /api/settings returned 200.
✅ Code review register_static_mime_types() runs once before StaticFiles/SPA mounting, and nothing else in the repo calls mimetypes.init() to reset it. The old .js-only fix in routers/settings.py is removed and now covered by the helper. Security allowlist, localhost middleware and DB untouched; no debug leftovers.
✅ New unit tests test_mime_types.py: 3 passed. Covers guess_type overrides and the Content-Type headers a real StaticFiles mount sends.
✅ Full pytest vs master baseline PR: 21 failed, 147 passed. The same 21 tests fail on a clean origin/master worktree (diff of the failure lists is identical; e.g. test_devserver_security shell-runner tests). Not related to this change.
✅ ruff / mypy ruff: All checks passed. mypy: 24 errors in 9 files, same count on master, none in the changed files.
✅ UI lint and build lint: 0 errors, 6 warnings; tsc -b && vite build succeeded.
✅ Browser render (Playwright) With the corrupted registry, the app on :5345 loaded 2 stylesheets (322 rules) and --primary resolved. 0 console errors or warnings. Layout is the same at 390x844.
⏭️ UI e2e suite The PR changes no UI code (backend MIME handling only).
⏭️ Real Windows verification No Windows host available. The registry corruption was simulated via mimetypes.add_type, which is the same mechanism mimetypes uses when it reads the Windows registry.
🧪 Commands run
Command Result
git diff origin/master...HEAD 4 files, +110/-4
ruff check . All checks passed
mypy . 24 errors in 9 files (identical on master; none in changed files)
python -m pytest -q 21 failed, 147 passed (same 21 failures on origin/master)
python -m pytest test_mime_types.py -v 3 passed
npm --prefix ui run lint 0 errors, 6 warnings
npm --prefix ui run build built successfully
python corrupt_run.py <worktree> 5345 + curl Content-Type of all index.html assets all correct types, 200
inproc.py (httpx ASGITransport, corrupted mimetypes) on master vs PR master css=text/plain, svg=octet-stream; PR css=text/css, svg=image/svg+xml

No browser screenshots were taken in this round.

Posted by cubefarm · merges automatically once GitHub's checks pass

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.

Layout terrible on Windows 11

1 participant