question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Warn if `next/dynamic` is not used in the top level of a module

See original GitHub issue

Feature request

Is your feature request related to a problem? Please describe.

next/dynamic relies on specific optimizations in order to be able to load the dynamic modules server-side as React doesn’t allow waiting for a promise to load. In order to do so it relies on the top level loading order of esmodules to register the function to be awaited server-side before rendering.

Generally this should look something like this:

import dynamic from 'next/dynamic'

// Top level to register the dynamic import function to be awaited
// React.lazy has the same API in that sense https://reactjs.org/docs/code-splitting.html#reactlazy
const DynamicComponent = dynamic(() => import('../components/hello'))

function Home() {
  return (
    <>
      <DynamicComponent />
    </>
  )
}

export default Home

We’ve seen quite a few times that people try to do this pattern instead:

import dynamic from 'next/dynamic'

// This does not work and breaks pre-rendering rendering of the dynamic import
// As a side-effect of using this approach you also mark all files (`../components/*`) 
// to be bundled by webpack as it does not know what the value of layout will be (maybe there's only 3 possible values)
function Home(props) {
  const DynamicComponent = dynamic(() => import(`../components/${props.layout}`))
  return (
    <>
      <DynamicComponent />
    </>
  )
}

export default Home

Describe the solution you’d like

In order to prevent having the user run into these issues we can show a warning through the Babel plugin that handles adding metadata to next/dynamic calls: https://github.com/vercel/next.js/blob/canary/packages/next/build/babel/plugins/react-loadable-plugin.ts

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:7 (7 by maintainers)

github_iconTop GitHub Comments

1reaction
wereHamstercommented, Nov 3, 2020

I’m still relying on dynamic() inside the page render function, due to aforementioned reasons, and I’m starting to run into limitations. Specifically, node.js keeps running OOM since the dynamic import matches so many files which need to be processed by webpack, babel etc. I would appreciate if Next.js offered a solution to my situation OOTB. Until then I think I can work around this by using a babel macro to statically (at compile time) generate a map of all dynamic components, eg.

/* pages/post/[id].js */

import dynamic from "next/dynamic";
import { myMacro } from "???";

const posts = myMacro`../../posts/*.mdx`
/* expands to:
const posts = {
  ["foo"]: dynamic(() => import(`../../posts/foo.mdx`)),
  ["bar"]: dynamic(() => import(`../../posts/bar.mdx`)),
  ["baz"]: dynamic(() => import(`../../posts/baz.mdx`)),
}
/*

export default ({ id }) => {
  const Component = posts[id];
  return <Component />;
};

I still fear though that Node.js may run OOM, since compiling the page requires webpack to traverse all the dynamically imported components, even though only a single one is used at any given page.

1reaction
wereHamstercommented, Jun 5, 2020

Please don’t.

I’m using next/dynamic inside my page render function, because I can’t reasonably maintain those dynamic components on the module top-level by hand. I have a lot of modules which I load dynamically based on page props, eg.

/* pages/post/[id].js */

import dynamic from "next/dynamic";

export default ({ id }) => {
  const Component = dynamic(() => import(`../../posts/${id}.mdx`));
  return <Component />;
};

I do not want to manually maintain the dynamic components outside of the render function, that is not ergonomic.

What would perhaps help is if I could do something like this, ie. let next build and maintain that list for me:

/* pages/post/[id].js */

import dynamic from "next/dynamic";

const Component = dynamic(({ id }) => import(`../../posts/${id}.mdx`));

export default ({ id }) => {
  return <Component id={id} />;
};
Read more comments on GitHub >

github_iconTop Results From Across the Web

Next.js dynamic import with custom loading component
dynamic() can't be used inside of React rendering as it needs to be marked in the top level of the module for preloading...
Read more >
Advanced Features: Dynamic Import - Next.js
dynamic() can't be used inside of React rendering as it needs to be marked in the top level of the module for preloading...
Read more >
25.33% Reduction in First Load JS with NextJS Dynamic Imports
A play by play in successfully reducing first load JS bundle size by 25% with code splitting via dynamic imports, and getting all...
Read more >
Best practices to increase the speed for Next.js apps
An application's speed is strongly related to the amount of time it takes to serve the application code, styles, and data to the...
Read more >
next - npm
If you are using some server only modules inside getInitialProps ... will show a warning if the resource is not used within 3...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found