Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dynamic Import makes NextJS development server very slow #1576

Open
5 tasks done
morrisseybr opened this issue Sep 26, 2023 · 22 comments
Open
5 tasks done

Dynamic Import makes NextJS development server very slow #1576

morrisseybr opened this issue Sep 26, 2023 · 22 comments
Labels
🐛 bug Something isn't working

Comments

@morrisseybr
Copy link

morrisseybr commented Sep 26, 2023

Package

  • lucide
  • lucide-react

Version

0.279.0

Browser

  • Other/not relevant

Operating system

  • Other/not relevant

Description

I'm attempting to utilize the dynamicIconImports object to create a unified component for rendering icons based on an icon name prop in NextJS 13 with the app router. I followed the example provided in the documentation, but it significantly slows down my development server. The time it takes for the initial compilation has increased from ~8 seconds to ~22 seconds, and the time for hot reloading even minor changes (such as a simple text modification) has gone from ~800ms to ~12 seconds.

image

I've tried changing the component from server-side to client-side rendering. I've also attempted to add the library to the transpilePackages list in the next.config.js file. I even experimented with using the dynamicIconImports object with a fixed name (ignoring the name prop), but none of these approaches seemed to help.

My solution to the problem was to rewrite the use of the next/dynamic function for importing the 'lucide-react' module and utilize the promise result to obtain the necessary icon. This restored the development server to its normal performance.

image

I believe that the way the dynamicIconImports feature is implemented causes the NextJS development server to read and process all the imports when it shouldn't be doing so during compilation.

I am planning to submit a pull request to enhance the consumption of Lucide.icons by introducing a simple IconsName type. Additionally, I will revise the example of dynamic usage within the NextJS environment to eliminate the use of the dynamicIconImports object.

Would anyone like to contribute to this issue I'm addressing? Your contributions would be greatly appreciated. Thank you!

Steps to reproduce

  1. Begin a NextJS 13 project following the instructions in the documentation (using the latest version - 13.5.3).
  2. Develop an Icon component as outlined in the lucide-react documentation, employing the 'dynamic' feature from NextJS and 'dynamicIconImports' from lucide-react.
  3. Import this component into a page and take note of the increased compilation time.

Checklist

  • I have searched if someone has submitted a similar issue before and there weren't any. (Please make sure to also search closed issues, as this issue might already have been resolved.)
@douglasrcjames
Copy link

This is happening to me as well, and this lag may be connected to my icons "flashing" because it takes a bit longer to load, which is not an ideal UX! Seems to be on Production and Development environments.

@O-Q
Copy link

O-Q commented Oct 15, 2023

according to the next.js document, it may be related to this:
dynamic() can't be used inside of React rendering as it needs to be marked in the top level of the module for preloading to work, similar to React.lazy.

@douglasrcjames
Copy link

according to the next.js document, it may be related to this: dynamic() can't be used inside of React rendering as it needs to be marked in the top level of the module for preloading to work, similar to React.lazy.

You linked the "Pages" directory for Next.js <v13, and not sure if this applies to the app structure of Next.js 13+, but I tried poking around and still couldn't get to work. If anyone can get dynamic icon importing to work without slowing down pages tremendously, I would love to figure this out!

@kisstamasj
Copy link

kisstamasj commented Nov 9, 2023

i have the same issue 🫤 when i run in production environment does not slow, but the icons are flashing when the page re rendering

@gropaul
Copy link

gropaul commented Nov 10, 2023

Same issue here ✋

@gracefullight
Copy link

Screenshot 2023-11-13 at 8 51 23 AM

I discovered that the lucide-react module, listed in transpilePackages within my next.config.js, is consuming approximately 9MB. This large footprint appears to be impacting the node.js performance adversely.

To provide some context, my current configuration utilizes dynamicImport, which I presumed would help in optimizing the load times and overall performance. However, with the substantial size of lucide-react, I'm not observing the expected efficiency.

I'm contemplating disabling dynamicImport as a potential solution to this issue. However, before proceeding with this change, I wanted to reach out to the community for insights and recommendations.

Here are my specific questions:

  1. Have others experienced similar issues with large module sizes in transpilePackages affecting performance?
  2. Is turning off dynamicImport a viable solution in this scenario, or are there alternative approaches that I should consider?

Thank you.

@hannesuw
Copy link

I'm facing the same issue.
It took more than 10 seconds on development mode to compile a page while using Dynamic Icon.

@morrisseybr
Copy link
Author

morrisseybr commented Nov 16, 2023

Any one trying the new exemple I make for using it with NextJS?

Please try and send me feedback, I will try to help you guys. For me the new implementation works like a charm.

@MrVibe
Copy link

MrVibe commented Jan 11, 2024

I had an infinite loading issue with dynamic imports
⨯ node_modules/lucide-react/dynamicIconImports.js:1395
export { dynamicIconImports as default };
^^^^^^

@github-actions github-actions bot removed the Stale label Jan 13, 2024
@murfidaz
Copy link

hello, how do I use it? because I save the icon name in the database, is there an example?

@IanMirandaDev
Copy link

Same issue here. I have 5k modules for each compilation in hotreload what tooks 40 secs to load.

I'm using the versions:
"lucide-react": "^0.321.0"
"next": "14.1.0"D

image

@dawidseipold
Copy link

Any one trying the new exemple I make for using it with NextJS?

Please try and send me feedback, I will try to help you guys. For me the new implementation works like a charm.

Sure it worked fine and removed the lag. But any idea on how to remove the unnecessary reloading of the icons on every page redirect?

@ericfennis
Copy link
Member

ericfennis commented Feb 12, 2024

Sorry for the late reply, I was a bit busy with other issues and PRs.
I'm not sure how to fix this issue. This is one of the caveats of using dynamic imports and this huge object with dynamic improts. Each dynamic import is linked to a separate module. So when starting a dev server or starting the build process each module declared in the dynamicIconImports object will go through the compiler because each module can be "possibly" used. The compiler doesn't know which icons are passed through the dynamic import object.

So you maybe have 12 icons in you database this object still imports all 1400+ icons on build time. But will be dynamically loaded.

So there is no easy fix.

Also the suggestion and docs change from @morrisseybr is not really a fix, this is just moving everything from lucide-react to a separate module. In this case using it this way is even more preformant:

import { LucideProps, icons } from 'lucide-react';

interface IconProps extends LucideProps {
  name: keyof typeof icons;
}

const Icon = ({ name, ...props }: IconProps) => {
  const LucideIcon = icons[name];

  return <LucideIcon {...props} />;
};

export default Icon;

Note: This only recommended when using the app router with React Server components, otherwise all icons will be shipped to the frontend as well.

So we could create a separate sections in the docs about the app router and pages router.

@weiying-chen
Copy link

weiying-chen commented Feb 25, 2024

Note: This only recommended when using the app router with React Server components, otherwise all icons will be shipped to the frontend as well.

So what if one wants to use Lucide icons using the app router with React client components (with a component similar to the one you shared)?

@kisstamasj
Copy link

kisstamasj commented Feb 26, 2024

I use like this: https://lucide.dev/guide/packages/lucide-react#icon-component-example
and its works just fine.
I don't know what is your use case, but the dynamic import is useful if you want to make an icon selector component for a cms.

@weiying-chen
Copy link

weiying-chen commented Feb 26, 2024

Isn't that the same implementation @ericfennis shared?

He said:

Note: This only recommended when using the app router with React Server components, otherwise all icons will be shipped to the frontend as well.

@app-rc
Copy link

app-rc commented Mar 13, 2024

Here is my client component, and works fine

'use client'

import { memo } from 'react'
import dynamic from 'next/dynamic'

const Icon = memo(({ name, ...props }) => {

	const LucideIcon = dynamic(() =>
		import('lucide-react').then((mod) => {
			return mod[name] || mod['Ban']
		})
	)

	return <LucideIcon {...props} />
})

Icon.displayName = 'Icon'

export default Icon

@ericfennis
Copy link
Member

@weiying-chen Indeed.
@app-rc Your code example will ship all icons to the frontend. This will affect your bundle size. I hope you're aware of this.

@SamuelOgbonnaeze
Copy link

SamuelOgbonnaeze commented May 10, 2024

Just saved me a lot of stress with this solution. thank you

@IonVillarreal
Copy link

Hello, any news on this problem?

@JavierLopezSCG
Copy link

Hey, I'm also experiencing this, it leaves a huge print on build size... Is there any other alternative? @ericfennis

@tylerlazenby
Copy link

One of the most significant issues is that they are trying to work with how react.js and SVG collide. SVGs are pretty light and, therefore, have traditionally loaded towards the end of DOM, so far down that hydration errors pop up unless you make them work with a useEffect and isLoaded solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🐛 bug Something isn't working
Projects
None yet
Development

No branches or pull requests