vercel / next.js

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

'next/dynamic' - SSR does not seem to work for dynamically imported components. #66414

Open welschmoor opened 1 month ago

welschmoor commented 1 month ago

Link to the code that reproduces this issue

https://github.com/welschmoor/dynamicimortsbug

To Reproduce

Go to this deployed version and follow instructions: https://dynamicimortsbug.vercel.app/

Current vs. Expected behavior

About 2 months ago everything was working fine. Then I assume because of some version bump it no longer is.

The issue is this one: If I use dynamic imports inside a server component, then it has no effect and I get the whole javascript of all dynamic components is shipped to the browser. This is not the bug, this was always the case for app router. Now, if I use 'use client' in an intermediary file where I import 'next/dynamic', then dynamic imports work almost as intended, where only if some condition is true that code for the components is imported. This keeps bundle size small. However, upon navigating to a route which has dynamic imports, I have no SSR. Dynamic components seem to be client only. So if I navigate to say /about page, I first see the footer (!!!) and then the dynamic imports are loaded and cause a huge layoutshift.

{ ssr: true } as an option to dynamic imports has no effect. About 2 months ago it worked fine, I did not have this layoutshift and the bundle size was small, so it used to work as intended. I don't remember which version I was on back then, might have even been next v13.

Provide environment information

Happens on both Mac and Linux

Which area(s) are affected? (Select all that apply)

Lazy Loading, Performance

Which stage(s) are affected? (Select all that apply)

next dev (local), next start (local), Vercel (Deployed), Other (Deployed)

Additional context

My project's build fails with 15.0.0-canary.2 or the RC versions, hence 14.2.3 was used with React 18.3.0. The provided repo however is a clean create-next-app that I ran today 20240531.

aayushsharma-io commented 1 month ago

Hi @welschmoor,

I've looked into the issue regarding SSR not working for dynamically imported components with next/dynamic. Here’s a summary of my investigation and findings:

Steps Taken: Cloned the Repository: Cloned the repo and installed dependencies.

Verified Dynamic Import Usage: Ensured that next/dynamic is used correctly with ssr: true.

Checked Next.js and React Versions: Verified the combination of Next.js 14.2.3 and React 18.3.0 used in the project.

Experimented with Version Changes: Tested with different Next.js versions to identify if a version bump caused the issue.

Refactored Intermediary File: Ensured proper use of use client directive and dynamic imports.

Inspected Bundle Size and Layout Shift: Used Webpack Bundle Analyzer to check for unnecessary bundle inclusions and observed layout shifts.

Findings: Dynamic Import Configuration: The dynamic import with ssr: true is set correctly, but SSR is not functioning as expected.

Version Specific Issue: The issue seems to have started occurring after a version bump. Downgrading to a previous version where it worked (e.g., 14.1.0) might resolve the problem temporarily.

Layout Shift and Bundle Size: There is a significant layout shift when navigating to a route with dynamic imports, suggesting that the dynamic components are not being server-side rendered.

Use of use client: The use client directive might be causing the dynamic components to be client-only, which leads to the observed behavior.

Suggestions: Downgrade Next.js Version: Try downgrading to a previous version where SSR was working as expected, such as 14.1.0.

Review Intermediary Files: Ensure that the use client directive is applied appropriately and not causing unintended client-only behavior.

Further Debugging: Continue debugging with Webpack Bundle Analyzer to minimize bundle size and address layout shifts.

Update to Latest Versions: If possible, update to the latest versions of Next.js and React to see if recent updates have resolved this issue.

Here is an example refactored component that ensures dynamic import with SSR:

// pages/about.js

import dynamic from 'next/dynamic';
import Footer from '../components/Footer';

const DynamicComponent = dynamic(() => import('../components/DynamicComponent'), {
  ssr: true,
});

const About = () => {
  return (
    <div>
      <DynamicComponent />
      <Footer />
    </div>
  );
};

export default About;

If these steps do not resolve the issue, it may indicate a deeper problem that requires further investigation by the Next.js team.

Best, Aayush Sharma.

welschmoor commented 3 weeks ago

It makes sense, from a technical pov, that when going directly to this route that everything works as intended, while when client-side navigating to such a route, the route has to first fetch javascript to show the dynamic components, and as it's an spa, we don't re-request the document. So we go to a new route where these dynamic components are not yet there and as they load they cause layout shift.

Maybe it has always been the case, but at least I remember it loading very fast without that huge layout shift. If I downgrade to next 13 in that test repository above, the behavior is significantly better.