Mixing static and dynamic data through layout (for i18n, multi-tenancy...) #64616
Replies: 11 comments 1 reply
-
Completely agree that a more robust handling of global level static data would be appreciated. I also encountered similar hurdles adding i18n to a recent project, but was able to work around it somewhat using the
Wanted to bring attention to this as a potential alternative. |
Beta Was this translation helpful? Give feedback.
-
And what's the consequence for dynamic pages? Will they still dynamically render after that? I'll try that asap thanks for the idea Edit: @alex-ketch this will give me an error like so if I use In my simplified example, it means the "userId" param has to be defined during rendering. So force-static doesn't seem to be compatible with having a dynamic parameter, it probably only works for a dynamic page that use no specific parameter. For instance this would work: This doesn't: Root layout Unless I am missing something |
Beta Was this translation helpful? Give feedback.
-
Just to be clear, you're talking about It just seems like this comment is surfacing a bug to me: #41980 (comment) It should be possible to have However, the solution you mention, should also work:
It should just be implied, which is a bug. This is just saying that the "params" are statically known, not that the pages that they render have to be fully static. If you use That lets us prerender part of the page (e.g. the head) even if most of the rest of it is still dynamic. So is there another issue that you hit when you try that? |
Beta Was this translation helpful? Give feedback.
-
@sebmarkbage I am still in the process of migrating to app folder (and learning) so I couldn't run full experiments on my current app, but to me it feels like The doc says that it lists params that will "statically generated at build time instead of on-demand at request time". To me "on-demand" rendering is static rendering on first request, not dynamic rendering, unless I've missed the point. I fixed the function name :) |
Beta Was this translation helpful? Give feedback.
-
The issue I was encountering might've been tangential, but was due to using:
The above raises an error stating |
Beta Was this translation helpful? Give feedback.
-
Facing the same issue here...
Not sure if related but using The same goes for |
Beta Was this translation helpful? Give feedback.
-
I've built a repro on Codesandbox: https://codesandbox.io/p/sandbox/mix-static-and-dynamic-djho81 Sadly I am hitting an unrelated weird hydration issue, despite using only server components. But you can see the architecture. When you build the code, "[lang]/[userId]" is treated as a static file. Codesandbox doesn't let me see the content of ".next" so I'll need to try to build locally to finally confirm whether a new chunk is created for each request user (so on-demand behaviour, which is different from dynamic rendering), which I strongly suspect. |
Beta Was this translation helpful? Give feedback.
-
I wonder if #44787 fixes it or if this is a separate issue. |
Beta Was this translation helpful? Give feedback.
-
Just tested... For me, at least, it doesn't.... :/ |
Beta Was this translation helpful? Give feedback.
-
Update, I've crafted a minimal reproduction eventually: https://github.com/eric-burel/nextjs13-mix-dynamic-static With generateStaticParams in layout
Here is what the code can look like for the dynamic page: // As is, this code will produce: "Error: A required parameter (userId) was not provided as a string in generateStaticParams for /[lang]/[userId]"
// Option 1: will trigger ISR = 1 page is stored per user, not what we want
// export const generateStaticParams = () => [];
// Option 2: explicit our intent to use dynamic rendering, doesn't work, same error
// export const dynamic = "force-dynamic";
export default function UserProfile({ params }: any) {
console.log("Rerendering user profile page");
return (
<div>
<p>Params from UserProfile: {JSON.stringify(params)}</p>
<Link href={`${params.lang}`}>Back to home</Link>
</div>
);
} If I remove generateStaticParams in layout
Summary
Finding the right combination is not obvious and I can't prerender my home in multiple languages. I can add I think I can now rephrase the expected behaviour more clearly: Current solutionRoot layout It's similar to how things would be done in v12 but it's hard to figure and defeat the purpose of layouts a bit. The layout seems to behave as expected though, it won't rerender the "french" layout multiple time during navigation between home and profile for instance, which is cool. Expected behaviourRoot layout Using "generateStaticParams" in a layout should implicitly behave as defining this same "generateStaticParams" function in all children pages except for pages is using/forcing dynamic rendering, in which case it should be ignored. |
Beta Was this translation helpful? Give feedback.
-
Small up on this: I think Partial Prerendering could solve this issue? |
Beta Was this translation helpful? Give feedback.
-
Describe the feature you'd like to request
Imagine the page structure as follow:
The home page has no user-specific data requirements. It is therefore possible to render it statically. Example : it loads a list of articles.
The profile page has user-specific data requirements. It is not possible to render it statically, dynamic rendering per-request is appropriate. Example : data about the current user.
The application also has global, static data requirements. This is the important part. Example: it can load a translation file for global elements ; the name of the company in a multi-tenant architecture ; a layout structure in a backend-driven architecture...
Let's use i18n as an example, eventhough this feature apply to all "segmented" use cases: A/B test, multi-tenant, personalization and friends.
My feature sums up this way:
Describe the solution you'd like
Using
generateStaticParams
in a layout should still allow the children pages to be dynamic.The layout would handle common, static data requirements, the dynamic pages would handle request-specific data requirements. Static pages can coexist peacefully with the dynamic pages too.
Related:
@leerob: this is a feature request I mentioned in the beta docs and i18n example thread, I've created a more formal feature request as suggested
Describe alternatives you've considered
0) Repro of my current setup with an additional empty generateStaticParams to build dynamic pages
See this codesandbox: https://codesandbox.io/p/sandbox/mix-static-and-dynamic-djho81
You will find an additional
generateStaticParams
in[lang]/[userId]
, needed to build, but it is unexpected.I am experiencing another issue, hydration doesn't work in the built version of this example for unknown reason. I suspect that every time I access a different user id, eg "/fr/42", a new chunk is created in
.next
for the user, therefore using on-demand rendering (~ISR) instead of dynamic which I want (SSR).1) Remove
generateStaticParams
from the layout. Instead, set them in the home page and all static pages.Problems:
This architecture is similar to how you would handle i18n in Next 12. It lead to issues at Devographics for the State of surveys, because each page bundle would be very fat, leading to slow page transitions.
We moved back to client-side fetching.
2) Use HTTP cache for the static pages
Problems:
3) Make dynamic pages use ISR
The sheer presence of a dynamic route param that is not present in the list returned by
generateStaticParams
will raise an issue. Therefore it's possible to setup ISR with a dummygenerateStaticParams
in the dynamic page that returns an empty array.4) cache per request?
The idea would be to use a dynamic render but try to cache everything to make it as fast as possible. This basically means making each "fetch" call "static", instead of using "generateStaticParams" explicitely. I haven't tested so not sure that works.
Anyway this loses the advantages of static rendering, the 1st request will still be expensive.
5) Just use dynamic rendering as soon as one page is dynamic
Say we have 50k users visiting 10 pages on average:
By setting up relevant caches everywhere, it can become acceptable by lowering the actual number of server/db requests, but the whole point of static rendering is too avoid doing that in the first place.
Each approach is probably worth a minimal reproduction, I will try to work on that if it can help but it may take me some time.
Beta Was this translation helpful? Give feedback.
All reactions