Replies: 5 comments 21 replies
-
Separate your Note that the
Example: // app/actions.ts
'use server'
export async function add(formData: FormData) {
const number = formData.get('number')
// Do something...
} import { add } from '@/actions'
export async function CustomModule() {
return (
<div>
<form action={add}>
<input type="number" name="number" />
<button type="submit">Add</button>
</form>
</div>
)
} Reference |
Beta Was this translation helpful? Give feedback.
-
You are correct that dynamically importing with template strings is not supported. This is because Next.js needs to be able to match webpack bundles / module ids to the specific dynamic() call and preload them before rendering. To implement true dynamic loading with Server Components, you will need to import the modules statically and then use dynamic() to lazy load them. Here is an example:
This will render the modules statically on the server, but will lazy load them on the client. This will improve performance by reducing the initial page load size. Here is an explanation of what is happening in this code:
This is a simple example of how to implement true dynamic loading with Server Components. You can use this technique to load any number of modules dynamically. |
Beta Was this translation helpful? Give feedback.
-
Hi, Have we asked ourselves, if this makes any sense at all? Server Components by definition, are "bundle-less", meaning that they are rendered server side, and no JS bundle is ever made for them. So, you could just do: import { Suspense, lazy } from "react";
const getModules = async () => {
return [
{ id: "1337", path: "foo" },
{ id: "1234", path: "bar" },
// { id: "3000", path: "baz" }, // this one would make it crash because it doesn't exist on my project
];
};
// to prevent it from generating this at build time once
export const dynamic = "force-dynamic";
export default async function Home() {
const modules = await getModules(); // e.g. loaded from a database
const ModuleJSX = Promise.all(
modules.map((mod) => {
const CustomModule = lazy(() => import(`./modules/${mod.path}`));
return (
<li key={mod.id}>
<Suspense fallback={"Loading..."}>
<CustomModule />
</Suspense>
</li>
);
})
);
return <ul>{ModuleJSX}</ul>;
} Right? You probably also need an Error Boundary around the custom module IIRC, in case it doesn't exist. |
Beta Was this translation helpful? Give feedback.
-
Hi there, what did you do in the end? I've recently hit a similar situation:
I understand the argument of not needing to be careful about what's pulled into a server component because it'll spit out a smaller JS bundle in the end. However, there's a case to be made for programmatically "selecting" the correct server component(s) for a particular dynamic route! Are we expected to build and manage logic (lookup tables etc.) to do this? |
Beta Was this translation helpful? Give feedback.
-
Sorry I haven't commented back on this issue – just to confirm, are y'all trying to lazy load client components or server components? https://nextjs.org/docs/app/building-your-application/optimizing/lazy-loading |
Beta Was this translation helpful? Give feedback.
-
Summary
Hello,
I'm trying to load Server Components dynamically:
Although
<CustomModule />
is rendered server-side, as soon as I'm using a Server Action inside<CustomModule />
, following error is shown which indicates<CustomModule />
now being a Client Component instead:I suspect dynamically importing with template strings (e.g.
../modules/${module.path}
) is not supported and leads to problems. But I would rather not import all custom modules to a map statically, because there could be many hundreds of them.Any ideas how to implement true dynamic loading with Server Components?
Additional information
No response
Example
CodeSandbox demo: https://codesandbox.io/p/sandbox/staging-mountain-k6w36f?file=%2Fapp%2Fmodules%2FCustomModuleA.tsx
Beta Was this translation helpful? Give feedback.
All reactions