Next.js: Dynamic SSR still renders on client

Created on 8 Jul 2019  路  8Comments  路  Source: vercel/next.js

I'm using dynamic with import to dynamically load components, and tell webpack to chunk them into separate files for a better client-side caching strategy.

I'm using this with export to produce a statically rendered site. It's necessary because I only have one index.js for the entire site, and everything is content driven. If I don't chunk the components, then all components are bundled in a single index.js which makes it a large download.

export const resolveComponent = name =>
  import(
    /* webpackChunkName: "foo" */ `./foo/${name}`
  );

export default function DynamicComponent(props) {
  const Component = dynamic(() => resolveComponent(props.name), {
    ssr: true,
  });
  return <Component {...props} />;
}

The above works great for client-side navigation with caching/preloading of chunks, but when I set the SSR flag on dynamic, it's still only loading on the client when the site is exported to html. This leads to slower page loading for SSR and glitches as each component loads on the client when the page is first rendered.

The expected behaviour when SSR is set is that the exported html pages will each have their baked-in components as part of the pre-rendered markup. I don't see any difference in behaviour whether ssr=true is set or not. Is this a bug?

I'm using NextJs 8.1.1-canary.69.

Most helpful comment

I run into the same pitfall. Maybe it is worth to mention in the documentation: dynamic + ssr works only with top level components and not in a render function.

All 8 comments

Only ssr: false is a value. By default this is already the behavior. The particular issue that you're having is that you're using non-standard import syntax. import() needs to be explicitly written without template strings. Furthermore the import() has to be inside the dynamic() call for us to be able to match webpack bundles / module ids to the specific dynamic() call.

Thanks, I tried simplifying to the following and getting exactly the same behavior for SSR:

export default function DynamicComponent(props) {
  const Component = dynamic(() => import('../foo/bar'));
  return <Component {...props} />;
}

The page renders empty, and then components drop in client-side.

@TheCodeKing please provide a full reproducible demo. We have integration tests covering this behavior so we know it should be working.

Thanks, I tried the with-dynamic-import-app example and that was working. It seems maybe it didn't like the way I was using dynamic within a function. I've refactored so dynamic imports are loaded outside of the function and it's working now.

You can't use dynamic() inside of rendering as it needs to be marked in the top level of the module, see https://github.com/zeit/next.js#basic-usage-also-does-ssr for an example. This is similar to how React.lazy works.

I run into the same pitfall. Maybe it is worth to mention in the documentation: dynamic + ssr works only with top level components and not in a render function.

I had same issue and waste time trying to figure out why this was not working in SSR, @timneutkens, I think @bobaaaaa suggestion鈥檚 is valid.

Feel free to send a PR to the documentation.

Was this page helpful?
0 / 5 - 0 ratings