Skip to content

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[NEXT-1550] App Router with output: export does not support useParams() on client #54393

Closed
1 task done
styfle opened this issue Aug 22, 2023 · 70 comments
Closed
1 task done
Labels
linear: next Confirmed issue that is tracked by the Next.js team.

Comments

@styfle
Copy link
Member

styfle commented Aug 22, 2023

Verify canary release

  • I verified that the issue exists in the latest Next.js canary release

Provide environment information

Operating System:
      Platform: darwin
      Arch: arm64
      Version: Darwin Kernel Version 22.5.0
    Binaries:
      Node: 18.17.1
      pnpm: 8.6.12
    Relevant Packages:
      next: 13.4.20-canary.2
      react: 18.2.0
      react-dom: 18.2.0
    Next.js Config:
      output: export

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

App Router, Static HTML Export (output: "export")

Link to the code that reproduces this issue or a replay of the bug

https://github.com/curated-tests/next-issue-48022

To Reproduce

The page in question is /app/blog-app/[slug]/page.tsx

next build

Describe the Bug

Fails with an error:

Error: Page "/blog-app/[slug]" is missing "generateStaticParams()" so it cannot be used with "output: export" config.

This is expected right now because its not implemented, but it would be nice to support this so that App Router can match Pages Router.

Expected Behavior

Ideally, the build should complete and navigation should work client side.

pnpm build
cd out
python3 -m http.server 3000
  • Visit http://localhost:3000
  • Click on Blog App (/blog-app/)
  • Click on One (/blog-app/one)
  • Should render the page on the client

Which browser are you using? (if relevant)

Chrome

How are you deploying your application? (if relevant)

python3 -m http.server 3000

NEXT-1550

@xray-robot
Copy link

xray-robot commented Sep 7, 2023

Perhaps there are dates when this is scheduled to be done? Or is it better to use Pages Router?

FYI: Gatsby allows you to use dynamic routers in static exports without configuring server-side redirects. That's the only thing stopping us from moving our PWAs from Gatsby to Next.js

@danbockapps
Copy link

I did not see this error on 13.4.13. I started seeing it when I upgraded to 13.5.3.

@petejodo
Copy link

Can confirm this is working on 13.4.13. I'm curious if the functionality is therefore a regression or a bug that's become a feature 😅

@GabenGar
Copy link
Contributor

But does it output the static page? If it doesn't and there is no error, then it's definitely a regression.

@styfle
Copy link
Member Author

styfle commented Oct 2, 2023

@petejodo What does "working" mean in this case? Previously there was no error message but it was failing silently. So in 13.5.0, a helpful error message was added explaining how to fix it.

See #48022 (comment) for more details.

However maybe there is a case when the error message shouldn't be printed? If you have code that was working with useParams() 13.14 as is no longer working in 13.15, please share the minimal code by creating a new issue and I'll get it fixed, thanks!

Please do NOT comment on this issue since it describes a new feature that needs to be implemented (not a regression).

@Frtrillo
Copy link

Frtrillo commented Oct 3, 2023

@petejodo What does "working" mean in this case? Previously there was no error message but it failing silently. So in 13.5.0, a helpful error message was added explaining how to fix it.

See #48022 (comment) for more details.

However maybe there is a case when the error message shouldn't be printed? If you have code that was working with useParams() 13.14 as is no longer working in 13.15, please share the minimal code by creating a new issue and I'll get it fixed, thanks!

Please do NOT comment on this issue since it describes a new feature that needs to be implemented (not a regression).

I can confirm that this issue persisted in version 13.4.13 as well. It failed silently as you said; there was no error during the build, but accessing the dynamic route resulted in a 404 error.
Sadly it appears that using dynamic routes with the app router and 'use client' is currently not possible. I hope it gets addressed soon, as it's just what's left for me, at least, to fully commit to the app router

@petejodo
Copy link

petejodo commented Oct 4, 2023

yeah I didn't see that at first and thought that it was working in my testing but I guess I somehow messed something up in my testing where I thought it was working but it definitely was not. Sorry, my mistake!

This put me in a bind because I misinterpreted the opening paragraphs to https://nextjs.org/docs/app/building-your-application/deploying/static-exports which made it seem I could port a SPA to nextjs and we just about finished porting it. That's my problem though, not yours' 😅 I think I can re-hack react-router back in even though that was giving me trouble at the start of the project

@C-W-D-Harshit

This comment has been minimized.

@eric-burel
Copy link
Contributor

Hi, is this related to the error encountered in @leerob SPA example? The error message seems surprising, and params are meant to be obtained via page props rather than the useParams hook, but I wonder if it is considered the same root issue

@goerlitz
Copy link

goerlitz commented Oct 13, 2023

Hi, I just started learning Next.js and I want to deploy my app as static SPA on Amazon S3. Hence, I added output: export. But I'm getting errors for the dynamic route pages using App Router.

  1. Error: Page "/datasets/[slug]" is missing "generateStaticParams()" so it cannot be used with "output: export" config. when I execute npm run build .
  2. After adding generateStaticParams() with some dummy values (because the real route params cannot be known at build time) I'm getting a runtime error (in dev mode) when calling the dynamic path with any other value. Error: Page "/datasets/[slug]/page" is missing param "/datasets/foo" in "generateStaticParams()", which is required with "output: export" config.
  3. When further adding 'use client' I get Error: Page "/datasets/[slug]/page" cannot use both "use client" and export function "generateStaticParams()".
  4. When I just add 'use client' but remove generateStaticParams() I'm getting Error: Page "/datasets/[slug]" is missing "generateStaticParams()" so it cannot be used with "output: export" config. again.

I'm stuck here. What am I supposed to do to get the dynamic routes working with the static export?

Maybe, I'm don't fully understand generateStaticParams() (yet), but when I use a dynamic route, I typically have many entries in a database that I wanna fetch and render on demand (either client or server side). I don't wanna pre-render millions of pages at build time. Moreover, I don't wanna rebuild the app whenever the database gets updated.

@eric-burel
Copy link
Contributor

eric-burel commented Oct 17, 2023

@goerlitz starting step 3 and 4 I think you get confused:

  • move the code that needs "use client" into a separate file, for instance:
// app/datasets/[slug]/page.tsx
export const generateStaticParams()
export async function YourPage() {
  return <ClientPage />
}
// app/datasets/[slug]/ClientPage.tsx
"use client"
export async function ClientPage() {
  const [someState] = useState("foo")
  return <div>{someState}</div>
}
  • As for generating the page with a dummy parameter, I am not sure what cause this error specifically (might but just a bug?), but anyway I think this approach won't work as is.

The thing is that if you use a dummy static param, Next only knows the dummy "/datasets/foo" route. So "/datasets/bar" won't work. You could do an URL rewrite from "/datasets/bar" to "/datasets/foo", but then the route parameter is lost.

You could opt for a query parameter instead.

Sadly until Next.js supports exporting dynamic routes that are not statically rendered like it did in Next 12 pages dir, I don't think you can use a dynamic route and do a static export, you should prefer a query parameter, + optionally an URL rewrite from a route param to a query param.

@goerlitz
Copy link

Thanks @eric-burel for the guidance.
Actually, after diving much deeper into Next.js, I realized that I was trying to make two different paradigms work together - which is a bad idea.

Having worked on SPA with Api backends in the past, I thought I could make Next.js output a SPA bundle with separate api code. Actually, I think that the first paragraph in https://nextjs.org/docs/app/building-your-application/deploying/static-exports is quite misleading in that sense:

Next.js enables starting as a static site or Single-Page Application (SPA), then later optionally upgrading to use features that require a server.

No, Next.js is not made for SPAs - it is a totally different paradigm with the goal to NOT do all rendering and routing in the browser but move more code to the server where computing is more efficient (SSR etc.). Hence, a typical Next.js app will never be an SPA (and should not be), because the application code is split up and runs on server and client likewise.

IMHO, for most applications - that usually have dynamic routing - the static export does not make sense to me at all.

@AndonMitev
Copy link

AndonMitev commented Oct 18, 2023

Does exists on 13.5.5 as well, I have tried to build a view with this routing structure:

/games
  [id]
     page.tsx

on production i had issues for previous versions, [id] was not found and it was navigating to home page, and now not even able to build to the this issue:

Error: Page "/page/[id]" is missing "generateStaticParams()" so it cannot be used with "output: export" config

@andreasfrey
Copy link

andreasfrey commented Oct 18, 2023

Can you please give an update, when this feature is planned? I mainly switchedto nextjs, because of the routing functionality. Now it forces me to host on a node server...

As a workaround i try out useing pages router again. [https://nextjs.org/docs/pages/building-your-application/routing/pages-and-layouts]

@goerlitz
Copy link

goerlitz commented Oct 18, 2023

Now it forces me to host on a node server...

@andreasfrey, this is what I meant with "Next.js follows a different paradigm" than SPA.
Running a Next.js app on a node server is the default deployment.

If you are trying to use Next.js to create a traditional SPA (with dynamic routes) that can be packaged for hosting on a CDN, then you are doing something (conceptually) wrong. This is not what Next.js was designed for.

If you want to move from an SPA to Next.js (with all the nice features, like SSR etc.), you should

  1. be okay with deploying everything to a node server (Vercel, Netlify, etc.) and changing your deployment pipelines
  2. identify and define suitable boundaries between client and server components in your app (ie. dynamic vs. static parts)

@goerlitz
Copy link

Maybe, I'm getting something wrong here.
@durchanek and @ramirorinaldi, can you explain why you voted down?

@andreasfrey
Copy link

@andreasfrey, this is what I meant with "Next.js follows a different paradigm" than SPA.
Running a Next.js app on a node server is the default deployment.

Maybe this is true.

I really like to develop React applications, because they are fast to build and require not much of a server (running even on CDN...). Now react enforces encourages me to use a framework and suggests next.js to use. And I did.

And now I wanted to implement a really basic use case - which is not possible anymore, because you insist on using a server component?

And yes it is true, I do not need server components. And I am sure many other people do't need them as well.

So, again I repeat the question:
When is it planned to implement dynamic routing on the client side? I am sure many ppl are waiting for it.

(I switched to Page Routes meanwhile ... maybe the next project is again simple React with react-router .....)

@ramirorinaldi
Copy link

@goerlitz with Pages Router you can use dynamic routes and output: "export", yes you need to provide all possible paths with getStaticPaths, but this is something not supported now with App Router.

As React itself suggests to use React-based frameworks, being NextJs its first option, one should expect to use it for a SPA without much conflicts, that's why I don't think you are doing something conceptually wrong when trying to do so...

Next does create an html file for each defined route, but in any case it can be up to the developer to sacrifice bundle size/load speed and load what they think it is "unnecessary JavaScript" to fully support dynamic routing for cases where you don't have the full list of possible paths

@magratheaner
Copy link

Totally agree with @ramirorinaldi. I landed in this situation because the official React docs recommended next.js and there were no (clear) warnings along the way for the use-case of statically-hosted SPAs using the app router paradigm.

So as long as the issue exists it would be nice to put some warnings about this somewhere in the next.js docs, and maybe also urge the React doc maintainers to do the same, to avoid too many others arriving here.

Apart from that it should be technically possible for next.js to support this if I'm not mistaken. So it would also be nice to see this on the roadmap down the line for later projects ☺️

@andreasfrey
Copy link

Totally agree with @ramirorinaldi. I landed in this situation because the official React docs recommended next.js and there were no (clear) warnings along the way for the use-case of statically-hosted SPAs using the app router paradigm.

So as long as the issue exists it would be nice to put some warnings about this somewhere in the next.js docs, and maybe also urge the React doc maintainers to do the same, to avoid too many others arriving here.

Apart from that it should be technically possible for next.js to support this if I'm not mistaken. So it would also be nice to see this on the roadmap down the line for later projects ☺️

You can use the Pagesd Router meanwhile (https://nextjs.org/docs/pages/building-your-application/routing)
image

@jserpapinto
Copy link

I have this page.tsx

import type { Metadata } from 'next'
import getStands from '@/lib/getStands'
import getStand from '@/lib/getStand'
import { notFound } from "next/navigation"


type Params = {
  params: {
    standId: string
  }
}

export async function generateMetadata({ params: { standId } }: Params): Promise<Metadata> {
  const standData: Promise<Stand> = getStand(standId)
  const stand: Stand = await standData

  if (!stand) {
    return {
      title: "stand not found!",
      description: "stand not found!"
    }
  }

  return {
    title: stand.name,
    description: `This is the page of ${stand.name}`
  }
}


export default async function StandPage({ params: { standId } }: Params) {

  const standData: Promise<Stand> = getStand(standId)
  const stand: Stand = await standData

  if (!stand) return notFound()
  
  return (
    <div>{JSON.stringify(stand)}</div>
  )
}

// generate static params function
export async function generateStaticParams() {
  const standsData: Promise<Stand[]> = getStands()
  const stands: Stand[] = await standsData

  console.log(stands)

  return stands.map((stand) => ({
    params: {
      standId: stand.id
    }
  }))
}

And also getting:

Error: Page "/[standId]" is missing "generateStaticParams()" so it cannot be used with "output: export" config.

@goerlitz
Copy link

same issue. Is there any solution?

No, unfortunately not. output: export is meant for static site generation of a fixed number of predefined content items (like Blog, documentation pages, a catalog, ...).

If you want to develop a fully dynamic SPA where the rendered pages depend on the user status and interactions, you should not use output: export but embrace the server side rendering of Next.js (and using Vercel is the easiest option to do so).

@GabenGar
Copy link
Contributor

GabenGar commented Oct 21, 2023

@goerlitz
Your posts are coping because pages router allows to output static pages with dynamic params just fine, with the assumption that the consuming server will map its own routing logic to specific output static files.
So nextjs clearly wasn't "designed" to force you into a runtime nodejs server, it would be DoA otherwise, since convincing a team to switch a framework with only some routing changes is way easier than convincing a team to shove another cloud http server in the stack.
It's just an unfortunate combination of things like react docs recommending to start with nextjs, while nextjs recommending to start with app router which can't migrate a typical react SPA codebase anymore.

@fromthemills
Copy link

One additional thing I noticed is that when you try to "trick" the app router in returning a catch all route it still does not work because useParams returns only the params returned by generateStaticParams and not dynamically based on the current url.

// app/posts/[id]/page.js
import PostDetailsPage from "./PostDetailsPage"; 

export async function generateStaticParams() {
  return [{ id: "fallback" }];
}

export default function Page() {
  return <PostDetailsPage />;
}
// app/posts/[id]/PostDetailsPage
"use client";

import { useParams } from "next/navigation";

export default function PostDetailsPage() {
  const { id } = useParams(); // always returns 'fallback' also when you navigate to /posts/1
  return <div>Post: {id}</div>;
}
{
    "rewrites": [
        {
            "source": "posts/*",
            "destination": "/posts/fallback.html"
        }
    ]
}

@alexanderhorner
Copy link

alexanderhorner commented Oct 25, 2023

Here is a feature request and discussion outlining the issue and solutions more clearly: #55393 (comment)

@tischrei

This comment was marked as duplicate.

@steida

This comment was marked as duplicate.

@SebastianGode

This comment was marked as duplicate.

@munjalpatel

This comment was marked as duplicate.

@callmevari

This comment was marked as off-topic.

@steida

This comment was marked as off-topic.

@solomkinmv

This comment was marked as duplicate.

@dhmoon91

This comment was marked as duplicate.

@SebastianGode
Copy link

@leerob Are there any news rgarding this issue? Timeline for fix or something like that?

@michaelignacio

This comment was marked as duplicate.

@cfv1984
Copy link

cfv1984 commented Jan 26, 2024

Hello everyone! Just checking in to ask if this scenario is already supported by NextJS:

As a NextJS user
I have a NextJS application
I have a "use client" page.tsx in this application
I have this page.tsx file in a structure like so: /app/objects/[obj]/page.tsx
I want this page to render when the client types "https://my.url/objects/asdf"
I want 'asdf' in the previous example to be a string that I have zero beforehand knowledge about. Could exist, could not exist, could be a user ID, could be an eggplant emoji.
I want the obj param to exist and be set to "asdf" when I useParams().
I want "output:export" to not fail to build because of a missing generateStaticParams function I can't build.

Any news about this?

@ilovski5
Copy link

@cfv1984 It is not supported yet. Currently, the only way to achieve this is through the pages router.

@aniket-kulkarni
Copy link

@leerob When do you plan to fix this? Our team is relying on the feature.

@codiku-dev
Copy link

So it means that an app using next-intl or similar cannot work with capacitor ?

Since everything is wrapped with a [locale] folder ? Is there at least a work around ?

@SebastianGode
Copy link

You can use the pages router or you need to wait like all of use for an fix.

martinakrtzschmr added a commit to martinakrtzschmr/nextjs-portfolio that referenced this issue Feb 7, 2024
@devSahinur

This comment was marked as duplicate.

@pranavburnwal

This comment has been minimized.

@gax97
Copy link

gax97 commented Mar 18, 2024

Another workaround is to switch from using params to search params to get the ID or whatever in the URL

@ccmvn
Copy link

ccmvn commented Apr 3, 2024

We finally need a fix for this, is there any new information yet?

@rmonnier9
Copy link

rmonnier9 commented Apr 4, 2024

In fact, the documentation is pretty clear about it :
image

This is disappointing.
I hope this will evolve in the future because for me it is a deal breaker : it means you can't build SPAs with Next.js and no, Next.js is not very "versatile" as said in the documentation 😅
(yes, all SPAs use url params)

@vercel vercel locked and limited conversation to collaborators Apr 17, 2024
@balazsorban44 balazsorban44 converted this issue into discussion #64660 Apr 17, 2024

This issue was moved to a discussion.

You can continue the conversation there. Go to discussion →

Labels
linear: next Confirmed issue that is tracked by the Next.js team.
Projects
None yet
Development

No branches or pull requests