Scripts from root layout don’t appear first in document head, including beforeInteractive
#77104
Replies: 3 comments 3 replies
-
I'm facing the same issue. I want to use a global window variable in some components, which is initialized in a script with beforeInteractive strategy placed in the . However, sometimes the component hydrates earlier than expected, and beforeInteractive doesn't work as intended. |
Beta Was this translation helpful? Give feedback.
-
I'm also facing the same issue while trying to ensure that our cookie consent script is loaded before all the nextjs script chunks to ensure specific features are blocked until user has given consent. It seems like a common use case, is there a work around in the meantime? |
Beta Was this translation helpful? Give feedback.
-
@controversial It may come after those scripts, but the fetch priority is higher, so the browser starts downloading it sooner.
I think this part of the documentation needs fixing—the execution does not block hydration (contradicts a later sentence). I moved this to discussions because since we would need to provide a way execute a Script while blocking hydration 👀 |
Beta Was this translation helpful? Give feedback.
-
Link to the code that reproduces this issue
https://github.com/controversial/next-script-order-repro
To Reproduce
next build
next start
Current vs. Expected behavior
Right now, scripts added to the root layout
<head>
appear in the rendered document after “chunk“ scripts from webpack output. Here’s how it looks in the attached reproduction—the server HTML contains five “next.js scripts” before the inlineinject-polyfill
script that was rendered at the beginning of the rootlayout.tsx
’s head:This behavior is misleading (or incorrect?) based on the docs—which say:
This ordering of scripts prevents the use case I showed in the reproduction: conditionally injecting a polyfill that might be needed for client component rendering.
If such an inline script could appear above the webpack chunks, it could inject a polyfill whose load blocks page hydration, which is my desired behavior. Under the current system (where Next.js scripts are always initiated first) it’s a race condition between them and the polyfill—the Next.js have already started loading before we have a chance to perform feature detection and inject a blocking polyfill script above them.
Within the reproduction, currently, the console logs:
injecting blocking polyfill script
client component mounted
polyfill script loaded, *after* component mounted
Even though it was injected as a blocking script at the beginning of <head>, it didn’t get a chance to block loading Next.js chunks, because it wasn’t injected until *after* Next.js chunk scripts had already started loading
I expect it to log:
injecting blocking polyfill script
polyfill script loaded
client component mounted
Provide environment information
Operating System: Platform: darwin Arch: arm64 Version: Darwin Kernel Version 24.2.0: Sun Nov 3 20:52:07 PST 2024; root:xnu-11215.60.405~54/RELEASE_ARM64_T6000 Available memory (MB): 16384 Available CPU cores: 10 Binaries: Node: 22.8.0 npm: 10.8.2 Yarn: 1.22.22 pnpm: N/A Relevant Packages: next: 15.0.4-canary.29 eslint-config-next: N/A react: 19.0.0-rc-b01722d5-20241114 react-dom: 19.0.0-rc-b01722d5-20241114 typescript: 5.3.3 Next.js Config: output: N/A
Which area(s) are affected? (Select all that apply)
Developer Experience, Navigation, Script (next/script), Webpack
Which stage(s) are affected? (Select all that apply)
next build (local), next start (local), Vercel (Deployed)
Additional context
I want to use an inline script for injecting polyfills because it avoids shipping the polyfill code to users that don’t need it.
I don’t want the polyfill code itself bundled as part of the root layout, because that increases the bundle size unnecessarily for all users. I’m okay with trading slightly slower load times on outdated browsers for better performance on recent browser versions.
Cloudflare’s polyfill service ships only the necessary features based on user-agent, but injecting the script after performing feature detection allows to avoid even waiting for the server roundtrip for users who would be receiving empty polyfills.
This problem affects both the “vanilla”
<script>
tag and the<Script>
component fromnext/script
Beta Was this translation helpful? Give feedback.
All reactions