Files
cloudflare__vinext/.gitignore
T
Xplod13 33be48648d fix(script): register src beforeInteractive scripts and mark hoisted output (#2019)
## Summary
- Register `beforeInteractive` Scripts with `src` through
  BeforeInteractiveContext so they are hoisted into <head> ahead of
  interactive, exactly like the inline form (previously they bypassed the
  registry and rendered in source order, after React Float's head content).
- Suppress the client React render for both inline AND src beforeInteractive
  Scripts in the App Router so the hoisted tag is never duplicated.
- Tag every hoisted script with Next.js's `data-nscript="beforeInteractive"`
  marker.
- Map `crossOrigin` -> `crossorigin` and `referrerPolicy` -> `referrerpolicy`
  on hoisted scripts (parity with Next.js set-attributes-from-props).
- Extract `renderBeforeInteractiveInlineScripts` into a dedicated, pure module
  (before-interactive-head.ts) so the emit path is unit-testable.

## Root Cause
The beforeInteractive SSR branch computed `inlineContent = src ? null : ...`
and only registered when `inlineContent !== null`, so any Script with a `src`
was never captured by the registry and never spliced into <head>; it stayed
where the user wrote it, behind React Float's hoisted resource hints, defeating
the before-interactive guarantee. Hoisting src scripts then requires the client
to stop rendering them through React (the React-created <script> never executes
and would only add a duplicate DOM node), so the client dedupe condition is
aligned with the SSR registration condition. The hoisted output also lacked
Next.js's `data-nscript` marker, and REACT_TO_HTML_ATTR omitted
crossOrigin/referrerPolicy, so those attribute names did not match Next.js's
lowercased output.

## References
- Fixes #2016
- Next.js: .nextjs-ref/packages/next/src/client/script.tsx (data-nscript,
  src/inline registry parity), set-attributes-from-props.ts (lowercased attrs)
- Ported: test/e2e/app-dir/script-before-interactive/script-before-interactive.test.ts

## Verification
- CI=true pnpm test tests/script.test.ts tests/script-head-ordering.test.ts
  tests/nextjs-compat/script-nonce.test.ts tests/shims.test.ts -> 1139 passed
- CI=true npx vp check on all changed files -> pass

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 23:38:06 +01:00

60 lines
986 B
Plaintext

node_modules/
dist/
out/
*.tsbuildinfo
.vite/
.turbo/
.ecosystem-test/
.next/
.wrangler/
test-results/
playwright-report/
out-e2e
# Environment + secrets
.env
.env.*
!.env.example
# wrangler convention for local-only secrets passed to `wrangler dev`
.dev.vars
.dev.vars.*
# Logs / coverage
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
coverage/
reports/
# Worktrees
.worktrees/
.claude
# Next.js reference clone (for searching source/tests)
.nextjs-ref/
# OS / editor
.DS_Store
.idea/
.vscode/
.claude/
.codex/
# Nix
result
result-*
# The Nix `result` pattern above also matches Next.js compat fixture routes
# named `result`; re-include them so they don't silently fall out of tracking.
!tests/fixtures/root-layout-redirect/app/result/
.direnv/
.corepack/
.vinext
next-env.d.ts
# Leaked temp fixtures from the oxlint prefer-shared-utils rule test
# (normally cleaned up in afterEach; ignore so a crashed run can't commit them).
__lint_rule_fixtures__-*