Skip to content

Stop shipping apps that render unstyled in dev - #1

Open
willtoth wants to merge 1 commit into
mainfrom
fix/dev-server-renders-unstyled
Open

Stop shipping apps that render unstyled in dev#1
willtoth wants to merge 1 commit into
mainfrom
fix/dev-server-renders-unstyled

Conversation

@willtoth

Copy link
Copy Markdown
Collaborator

security.csp: true blanks every Hawk app in npm run dev.

Astro computes the sha256 hashes that let a policy permit inline <style>/<script> blocks only at build time. The dev server injects Tailwind's stylesheet inline for hot-reload, so those blocks carry no hash and style-src 'self' blocks all of them. document.styleSheets comes back empty and the page falls back to Times New Roman and blue underlined links.

Nothing caught it, because every gate tests production:

Gate What it runs
npm run check astro build
Playwright webServer npm run build && npm start
/health returns JSON

npm run dev is the one mode nothing tests and the only broken one — and it is what the create-hawk-app skill starts and hands to the user. A live run ended with the app declared "built and working" over a blank page, then spent ~40 minutes and a sudo apt-get getting a browser to find out why.

Changes

  • astro.config.mjs — a hawk-csp-off-in-dev integration turns CSP off for command === "dev" only. Production is untouched.
  • scripts/render-check.mjs + npm run check:render — probes the running server for this class of fault: inline blocks a policy will block, stylesheets that never arrive. No browser, no dependencies, uses built-in fetch.
  • scripts/doctor.mjs — stop reporting the app's own dev server as a port conflict. It sent people hunting for a clash that wasn't there.
  • Decision recorded in docs/ARCHITECTURE.md; AGENTS.md now points at check:render for anything that changes how a page looks.

Verification

  • With csp: true restored, check:render exits 1 and names the blocked styles.
  • With the fix, dev serves no policy and 65 KB of inline CSS is applied; production still emits 9 sha256 hashes.
  • npm run check green: 0 type errors, 4 tests, clean build.
  • Fresh clone → npm cinpm run devcheck:render passes end to end.
  • Doctor verified for all three port cases: free, held by this app, held by something else.

🤖 Generated with Claude Code

https://claude.ai/code/session_01KwyEjaCaTwhkRkTUMq9hep

Astro computes the sha256 hashes that let a Content-Security-Policy permit
inline <style>/<script> blocks only at build time. The dev server injects
Tailwind's stylesheet inline for hot-reload, so those blocks carry no hash and
`security.csp: true` blocked every one of them: `npm run dev` served a page with
no styles applied at all, falling back to Times New Roman and blue links.

Nothing caught it. `npm run check` builds for production, the Playwright
webServer runs `npm run build && npm start`, and /health returns JSON -- so
every gate tested a mode that was fine, while the only mode a person actually
opens was broken. A live run of the create-hawk-app skill ended with the app
declared "built and working" over a blank page.

- astro.config.mjs: a `hawk-csp-off-in-dev` integration turns CSP off for
  `command === "dev"` only. Production still emits the full policy with hashes.
- scripts/render-check.mjs + `npm run check:render`: probe the *running* server
  for this class of fault -- inline blocks a policy will block, stylesheets that
  do not arrive -- with no browser and no dependencies.
- scripts/doctor.mjs: stop reporting the app's own dev server as a port
  conflict. It sent people hunting for a clash that was not there.

Verified both ways: with `csp: true` restored, check:render exits 1 naming the
blocked styles; with the fix, dev has no policy and production keeps 9 hashes.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KwyEjaCaTwhkRkTUMq9hep
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