vercel / next.js

The React Framework
https://nextjs.org
MIT License
125.96k stars 26.87k forks source link

Just calling `useSearchParams` hook in a client component breaks static page rendering of whole app (breaks static generation of meta tags) #48335

Open tmaihoff opened 1 year ago

tmaihoff commented 1 year ago

Verify canary release

Provide environment information

npx --no-install next info

    Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.4.0: Mon Mar  6 21:00:41 PST 2023; root:xnu-8796.101.5~3/RELEASE_ARM64_T8103
    Binaries:
      Node: 18.9.1
      npm: 8.19.1
      Yarn: 1.22.19
      pnpm: N/A
    Relevant packages:
      next: 13.3.1-canary.6
      eslint-config-next: 13.2.4
      react: 18.2.0
      react-dom: 18.2.0

Which area(s) of Next.js are affected? (leave empty if unsure)

App directory (appDir: true), Metadata (metadata, generateMetadata, next/head, head.js)

Link to the code that reproduces this issue

https://github.com/tmaihoff/next-metadata-issue

To Reproduce

Reproduction example

This is my layout.tsx

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <ClientComponent />
      <body>{children}</body>
    </html>
  )
}

How to break static generation with useSearchParams

This is my ClientComponent breaking the static generation.

export default function ClientComponent() {
  const searchParams = useSearchParams();

  return (
    <div>
      <h1>ClientComponent </h1>
      <p>searchParams: {searchParams.toString()}</p>
    </div>
  )
}

With the above ClientComponent, the generated index.html looks like this. You can see that the <meta> tags are missing inside <head>. However they are present in <script>self.__next_f.push([1,'3: ...

<!DOCTYPE html>
<html id="__next_error__">
  <head>
    <script
      src="/_next/static/chunks/polyfills-c67a75d1b6f99dc8.js"
      nomodule=""
    ></script>
  </head>
  <body>
    <script
      src="/_next/static/chunks/webpack-057ba9cde9392c2a.js"
      async=""
    ></script>
    <script
      src="/_next/static/chunks/455-e3a12aac2a978f1a.js"
      async=""
    ></script>
    <script
      src="/_next/static/chunks/main-app-adc18e92199e3750.js"
      async=""
    ></script>
  </body>
</html>
<script>
  (self.__next_f = self.__next_f || []).push([0]);
</script>
<script>
  self.__next_f.push([1, '0:"$L1"\n']);
</script>
<script>
  self.__next_f.push([
    1,
    '2:I{"id":"611","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","async":false}\n4:I{"id":"8331","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","async":false}\n5:I{"id":"847","chunks":["185:app/layout-ef8499614f6208b4"],"name":"","async":false}\n6:I{"id":"8892","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","async":false}\n7:I{"id":"8880","chunks":["272:webpack-057ba9cde9392c2a","455:455-e3a12aac2a978f1a"],"name":"","as',
  ]);
</script>
<script>
  self.__next_f.push([
    1,
    'ync":false}\n8:I{"id":"7059","chunks":["931:app/page-0e5774f4785aa9aa"],"name":"","async":false}\n',
  ]);
</script>
<script>
  self.__next_f.push([
    1,
    '1:["$","$L2",null,{"assetPrefix":"","initialCanonicalUrl":"/","initialTree":["",{"children":["",{}]},null,null,true],"initialHead":["$L3",null],"globalErrorComponent":"$4","children":[["$","html",null,{"lang":"en","children":[["$","$L5",null,{}],["$","body",null,{"children":["$","$L6",null,{"parallelRouterKey":"children","segmentPath":["children"],"hasLoading":false,"template":["$","$L7",null,{}],"notFound":[["$","title",null,{"children":"404: This page could not be found."}],["$","div",null,{"style":{"fontFamily":"system-ui,\\"Segoe UI\\",Roboto,Helvetica,Arial,sans-serif,\\"Apple Color Emoji\\",\\"Segoe UI Emoji\\"","height":"100vh","textAlign":"center","display":"flex","flexDirection":"column","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"children":[["$","style",null,{"dangerouslySetInnerHTML":{"__html":"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}"}}],["$","h1",null,{"className":"next-error-h1","style":{"display":"inline-block","margin":"0 20px 0 0","padding":"0 23px 0 0","fontSize":24,"fontWeight":500,"verticalAlign":"top","lineHeight":"49px"},"children":"404"}],["$","div",null,{"style":{"display":"inline-block"},"children":["$","h2",null,{"style":{"fontSize":14,"fontWeight":400,"lineHeight":"49px","margin":0},"children":"This page could not be found."}]}]]}]}]],"childProp":{"current":[["$","main",null,{"className":"page_main__ibFHK","children":[["$","div",null,{"className":"page_description__s_Lqk","children":[["$","p",null,{"children":["Get started by editing ",["$","code",null,{"className":"page_code__Cdcue","children":"src/app/page.tsx"}]]}],["$","div",null,{"children":["$","a",null,{"href":"https://vercel.com?utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","target":"_blank","rel":"noopener noreferrer","children":["By"," ",["$","$L8",null,{"src":"/vercel.svg","alt":"Vercel Logo","className":"page_vercelLogo__1QD2W","width":100,"height":24,"priority":true}]]}]}]]}],["$","div",null,{"className":"page_center__GvJ9Y","children":[["$","$L8",null,{"className":"page_logo__M5piD","src":"/next.svg","alt":"Next.js Logo","width":180,"height":37,"priority":true}],["$","div",null,{"className":"page_thirteen__DLEbK","children":["$","$L8",null,{"src":"/thirteen.svg","alt":"13","width":40,"height":31,"priority":true}]}]]}],["$","div",null,{"className":"page_grid__2WZXq","children":[["$","a",null,{"href":"https://beta.nextjs.org/docs?utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","className":"page_card__ftWzl","target":"_blank","rel":"noopener noreferrer","children":[["$","h2",null,{"className":"__className_e7970e","children":["Docs ",["$","span",null,{"children":"-\u003e"}]]}],["$","p",null,{"className":"__className_e7970e","children":"Find in-depth information about Next.js features and API."}]]}],["$","a",null,{"href":"https://vercel.com/templates?framework=next.js\u0026utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","className":"page_card__ftWzl","target":"_blank","rel":"noopener noreferrer","children":[["$","h2",null,{"className":"__className_e7970e","children":["Templates ",["$","span",null,{"children":"-\u003e"}]]}],["$","p",null,{"className":"__className_e7970e","children":"Explore the Next.js 13 playground."}]]}],["$","a",null,{"href":"https://vercel.com/new?utm_source=create-next-app\u0026utm_medium=appdir-template\u0026utm_campaign=create-next-app","className":"page_card__ftWzl","target":"_blank","rel":"noopener noreferrer","children":[["$","h2",null,{"className":"__className_e7970e","children":["Deploy ",["$","span",null,{"children":"-\u003e"}]]}],["$","p",null,{"className":"__className_e7970e","children":"Instantly deploy your Next.js site to a shareable URL with Vercel."}]]}]]}]]}],null,null,[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/ffa6367fdf432817.css","precedence":"next.js"}],["$","link","1",{"rel":"stylesheet","href":"/_next/static/css/e5c2b8b025a6a123.css","precedence":"next.js"}]]],"segment":""}}]}]]}],null,null,[["$","link","0",{"rel":"stylesheet","href":"/_next/static/css/876d048b5dab7c28.css","precedence":"next.js"}]]]}]\n',
  ]);
</script>
<script>
  self.__next_f.push([
    1,
    '3:[[["$","meta",null,{"charSet":"utf-8"}],["$","title",null,{"children":"Create Next App"}],["$","meta",null,{"name":"description","content":"Generated by create next app"}],null,null,null,null,null,null,null,null,["$","meta",null,{"name":"viewport","content":"width=device-width, initial-scale=1"}],null,null,null,null,null,null,null,null,null,null,[]],[null,null,null,null],null,null,[null,null,null,null,null],null,[null,["$","meta",null,{"property":"og:title","content":"Create Next App"}],["$","meta",null,{"property":"og:description","content":"Generated by create next app"}],null,null,null,null,null,null,null,null,null,null,null,null,null],null,null,[null,[["$","link",null,{"rel":"icon","href":"/_next/static/media/metadata/favicon.603d046c.ico","type":"image/x-icon","sizes":"any"}]],[],null]]\n',
  ]);
</script>

How to fix it

Just removing the line useSearchParams from the ClientComponent does the trick. Using this

export default function ClientComponent() {
  return (
    <div>
      <h1>ClientComponent </h1>
    </div>
  )
}

results in the following index.html with statically generated <meta> tags:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <link
      rel="stylesheet"
      href="/_next/static/css/ffa6367fdf432817.css"
      data-precedence="next.js"
    />
    <link
      rel="stylesheet"
      href="/_next/static/css/e5c2b8b025a6a123.css"
      data-precedence="next.js"
    />
    <link
      rel="stylesheet"
      href="/_next/static/css/876d048b5dab7c28.css"
      data-precedence="next.js"
    />
    <title>Create Next App</title>
    <meta name="description" content="Generated by create next app" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta property="og:title" content="Create Next App" />
    <meta property="og:description" content="Generated by create next app" />
...

Describe the Bug

Just using the useSearchParams hook in a client component breaks the static site rendering of the whole app. This can be observed e.g. by the meta tags not being statically generated with npm run build. Just removing the hook from the code makes the static generation work.

Please check the Reproduction example.

Expected Behavior

useSearchParams should not affect the static site generation of server components of the app.

Which browser are you using? (if relevant)

No response

How are you deploying your application? (if relevant)

No response

NEXT-1444

HamAndRock commented 1 year ago

Wrap it in suspense, that should help. It's mentioned in beta docs for useSearchParams.

rtatarinov commented 10 months ago

This bug appears also with usePathname and Suspense doesn't help. I can't reproduce it, but I check logs and sometime users see the __next_error__ page instead of correct page

0xboga commented 10 months ago

Wrap it in suspense, that should help. It's mentioned in beta docs for useSearchParams.

For me it worked in Next 13.5.5.

hmtcelik commented 8 months ago

i tried to fix with Suspense as in docs but didnt work in Next 14.1.0

devSahinur commented 8 months ago

same issue

Edit by maintainer bot: Comment was automatically minimized because it was considered unhelpful. (If you think this was by mistake, let us know). Please only comment if it adds context to the issue. If you want to express that you have the same problem, use the upvote 👍 on the issue description or subscribe to the issue for updates. Thanks!