Issue with Dynamic Components Loading nuxt 3
Hello everyone,
I have a composable useComponentRegistry, which is supposed to load a component either from the core or from a custom registry if it exists. The function looks like this:
When I try to render the component dynamically like this:
I get errors during the build process : Cannot read properties of null (reading 'ce'), Cannot destructure property 'type' of 'vnode' as it is null, Warn: resolveComponent can only be used in render() or setup(), Unhandled error during execution of render function. After the build, there are no more errors, and the components work as expected.
When I pass the banners prop directly to the SliderBanners component like this, it works perfectly fine:
<SliderBanners :banners="banners"></SliderBanners>
I’m wondering if there’s something wrong with how I’m using useComponentRegistry for dynamic component loading or if there’s something specific I’m missing when passing props dynamically. Is there a best way to load my custom components if exist ? I'm currently blocked because the import cannot handle dynamic variables with subdirectories.
Thank you!
2 Replies
Hi @Tess. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:
----------------------
Your approach to dynamic component loading in Nuxt 3 is creative, but there are some important caveats and limitations with dynamic imports and component resolution in Nuxt 3 that are relevant to your issue.
Key Points from the Knowledge Sources
1. Dynamic Imports with Variables:
Nuxt's auto-imported components and the
While
- If you know all possible components ahead of time, you can create a mapping object that statically imports them and then select the component from this map. - If you want to use dynamic components with
Nuxt3 dynamic <component>
Docs > components If you have a more specific use case or need further clarification, please provide more details! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
Nuxt's auto-imported components and the
resolveComponent
helper require the component name to be a literal string at compile time. Passing a variable to resolveComponent
or trying to dynamically import components based on a variable path is not supported and will not work as expected. This is a known limitation, as described in several sources:
You cannot pass a variable to the resolveComponent() method.Nuxt3 dynamic <component> 2. Dynamic Imports with<component :is="resolveComponent(aVariableThatHoldsComponentName)" />
— This is Not OK ❌<component :is="resolveComponent('MyComponent')" />
— This is OK ✅<component :is="conditionalComponent" />
— This is OK ✅<component :is="getComponent(key)" />
— This is OK ✅
import.meta.glob
:While
import.meta.glob
can be used for dynamic imports, it is limited to static analysis at build time. The keys you use in the glob must match exactly the file paths, and you cannot use variables to construct these paths at runtime in a way that Vite (or Webpack) can statically analyze. This means that if your componentPath
is dynamic and includes subdirectories, you must ensure that the keys in your customComponents
and coreComponents
objects match the exact import paths.
3. Best Practices for Dynamic Components in Nuxt 3:- If you know all possible components ahead of time, you can create a mapping object that statically imports them and then select the component from this map. - If you want to use dynamic components with
<component :is="...">
, you should either use globally registered components or import them directly and pass the reference, not a string, to the is
prop.
- For truly dynamic scenarios, you may need to rethink the architecture to avoid runtime dynamic imports, or accept the limitations and handle missing components gracefully.
Why Your Approach Causes Build-Time Errors
- The errors like Cannot read properties of null (reading 'ce')
and resolveComponent can only be used in render() or setup()
are likely due to the fact that the component reference returned by your composable is not available or not properly resolved at the time the template is compiled.
- Nuxt/Vue expects the is
prop to receive either a component reference or a string that matches a globally registered component. When you use a composable that returns an async component, it may not be ready at the time the template is rendered, especially during SSR or build.
Recommendations
- Static Mapping: If possible, create a static map of your components:
Then use:
- Global Components: If you want to use string names, register your components globally (either by directory or .global.vue
suffix), but be aware of the performance implications as all global components are included in the bundle and available everywhere Docs > components.
- Dynamic Imports with import.meta.glob
: If you must use import.meta.glob
, ensure your keys match exactly and that you handle the async nature of the returned component. You may need to use <Suspense>
or handle loading states explicitly.
- Avoid Passing Composable Calls Directly in Template: Instead of calling useComponentRegistry
directly in the template, call it in your setup()
and assign the result to a variable, then use that variable in the template. This ensures the component is resolved before rendering.
Example Adjustment
Summary
- You cannot dynamically resolve component names at runtime using variables with resolveComponent
or dynamic imports in the way you intend.
- Use static mapping or global registration for dynamic components.
- Always resolve the component in setup()
and pass the reference to the template.
If you need more flexibility, you may need to reconsider your component architecture or accept the limitations of dynamic imports in Nuxt 3.Nuxt3 dynamic <component>
Docs > components If you have a more specific use case or need further clarification, please provide more details! ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
<@1360230519731916952> Kapa.ai is still learning and improving, please let me know how I did by reacting below.