Nextjs includes all client components in the bundle when at least one client component is rendered from a server component (app-folder)
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 142k
- Forks
- 32.4k
- Avg merge
- 2d 14h
- Merged PRs (30d)
- 351
Description
Link to the code that reproduces this issue
https://github.com/EvgeniyKorshun/nextjs-includes-client-code-for-all-pages
To Reproduce
- Start the app in prod mode (npm run build && npm run start);
- Open http://localhost:3000;
- Check the Source of the page.
Current vs. Expected behavior
Current behavior:
Next.js includes ClientComponent2 in the bundle, even though ServerComponent2 is not used on the current page.
Expected behavior:
Only ClientComponent1 should be included in the bundle.
Provide environment information
Operating System:
Platform: darwin
Arch: arm64
Version: Darwin Kernel Version 23.6.0: Mon Jul 29 21:14:30 PDT 2024; root:xnu-10063.141.2~1/RELEASE_ARM64_T6000
Available memory (MB): 16384
Available CPU cores: 8
Binaries:
Node: 20.13.1
npm: 10.5.2
Yarn: 1.22.18
pnpm: 9.5.0
Relevant Packages:
next: 15.0.0-canary.146 // Latest available version is detected (15.0.0-canary.146).
eslint-config-next: N/A
react: 19.0.0-rc-7771d3a7-20240827
react-dom: 19.0.0-rc-7771d3a7-20240827
typescript: N/A
Next.js Config:
output: N/A
Which area(s) are affected? (Select all that apply)
SWC, Webpack
Which stage(s) are affected? (Select all that apply)
next dev (local), next build (local)
Additional context
We are currently using the latest stable version of Next.js and it appears that it includes all client components in the bundle when at least one client component is rendered from a server component. (the same issue reproduced for latest canary version)
In our project we have a JAMStack architecture, it has a single catch-all route [[...slug]] that handles dynamic page generation by pulling content from a CMS. There is a file that imports multiple components in the following format (these components are not marked with use-client, and we have tried various import strategies, including conditional import, dynamic import, and lazy loading, but without any success):
const HeaderSection = dynamic(() => import('./components/HeaderSection'));
const TextSection = dynamic(() => import('./components/TextSection'));
const VideoSection = dynamic(() => import('./components/VideoSection'));
const TestSection = dynamic(() => import('./components/TestSection'));
const Components = {
HeaderSection,
TextSection,
VideoSection,
TestSection,
};
export const getComponent = (key) => Components[key]
Even when rendering a simple test page that only contains a basic block with no additional content, the entire bundle still includes all the use-client components from these sections. As a result, the page size grows excessively, often exceeding 1 MB.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with the linked reproduction repository, run npm run build && npm run start, open the root page, and inspect its source and generated bundle. Trace how the app-folder ServerComponent2 and ClientComponent2 imports are collected by the Next.js SWC/Webpack pipeline. Done means the reproduced page includes ClientComponent1 without bundling unused ClientComponent2.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- nextjs, react, webpack
- Domain
- build-system, frontend, performance
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100