N
Nuxtโ€ข2mo ago
Mubo

Is it possible to use 'hydrate-never' with '<component :is="....' ?

Is it possible to use 'hydrate-never' with '<component :is="....' ? When we tried using it like this the 'hydrate-never' part got ignored and it was working the same as before. Is there any workaround for this ? We would like to use dynamic pages/components with the new delayed hydration feature.
23 Replies
kapa.ai
kapa.aiโ€ข2mo ago
Hi @Mubo. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave: ---------------------- Based on the knowledge sources, there are some limitations with using delayed hydration in Nuxt, particularly with dynamic components. Currently, Nuxt's built-in lazy hydration has specific constraints: 1. It only works in single-file components (SFCs) 2. It requires you to define the hydration prop directly in the template (rather than spreading via v-bind) 3. It does not work with direct imports from #components As mentioned in the documentation: "Currently Nuxt's built-in lazy hydration only works in single-file components (SFCs), and requires you to define the prop in the template (rather than spreading an object of props via v-bind)." Delayed Hydration Documentation The issue you're experiencing with hydrate-never being ignored when used with dynamic components (<component :is="...") aligns with these limitations. The dynamic component resolution happens at runtime, while the hydration strategies need to be determined during the build process. For a workaround, you have a few options: 1. Use a predefined map of components with their hydration strategies already applied:
const componentMap = {
key1: resolveComponent('MyComponentA'), // with hydrate-never applied to the component itself
key2: resolveComponent('MyComponentB'),
key3: resolveComponent('MyComponentC'),
}
const getComponent = (key) => {
return componentMap[key]
}
const componentMap = {
key1: resolveComponent('MyComponentA'), // with hydrate-never applied to the component itself
key2: resolveComponent('MyComponentB'),
key3: resolveComponent('MyComponentC'),
}
const getComponent = (key) => {
return componentMap[key]
}
2. Make your components global (though this has performance implications):
<template>
<component :is="componentName" hydrate-never />
</template>
<template>
<component :is="componentName" hydrate-never />
</template>
This works only if the component is registered globally, as mentioned in the Stack Overflow post about dynamic components in Nuxt 3. 3. Consider using the new lazy hydration macros that were recently introduced (in PR #31192), which provide an explicit import solution:
<script setup lang="ts">
const LazyHydrationMyComponent = defineLazyHydrationComponent(
'never',
() => import('./components/MyComponent.vue')
)
</script>
<template>
<div>
<!-- This component will never be hydrated by Vue. -->
<LazyHydrationMyComponent />
</div>
</template>
<script setup lang="ts">
const LazyHydrationMyComponent = defineLazyHydrationComponent(
'never',
() => import('./components/MyComponent.vue')
)
</script>
<template>
<div>
<!-- This component will never be hydrated by Vue. -->
<LazyHydrationMyComponent />
</div>
</template>
However, this is a newer feature and may not be available in your current Nuxt version. The core issue is that the dynamic component resolution with :is doesn't properly integrate with the hydration strategies in the current implementation. This is a known limitation of how Nuxt processes these special hydration props. ---------------------- Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: ----------------------
kapa.ai
kapa.aiโ€ข2mo ago
<@659047750381338624> Kapa.ai is still learning and improving, please let me know how I did by reacting below.
Mubo
MuboOPโ€ข2mo ago
I did try points 1. and 2. and it didnt work. I will try point 3. Maybe another solution would be to write v-if for all of the components in the template and add Lazy prefix to them with correct hydration what do you think @kapa.ai @kapa.ai
kapa.ai
kapa.aiโ€ข2mo ago
Let me check the knowledge base for you again. One moment! :books: Sorry @Mubo, I seem to be having a bit of trouble. Don't worry though, I've pinged my support and they will try to fix me up! :technologist: Perhaps try again in 15mins?
manniL
manniLโ€ข2mo ago
I don't think so @Mubo as the component name can't be inferred. You'd have to do it manually I think
manniL
manniLโ€ข2mo ago
Nuxt
components/ ยท Nuxt Directory Structure
The components/ directory is where you put all your Vue components.
Mubo
MuboOPโ€ข2mo ago
Thank you @manniL ๐Ÿ™Œ
dataexcess
dataexcessโ€ข2mo ago
sorry can someone explain to me what the solution is? I'm stuck with the same problem I tried having a simple empty component called 'Page' with a slot.. I then would wrap my <component :is> components in a LazyPage... but that does not seem to work either @manniL could you take a look at my question? would appreciate it a lot. big fan of your channel ๐Ÿ˜€
manniL
manniLโ€ข2mo ago
thanks! ๐Ÿ™ The answer is - you can't with component :is directly you need to use an SFC regarding slots & no component :is: that might be sth. to raise, but a similar issue exists
dataexcess
dataexcessโ€ข2mo ago
@manniL Not sure if I understand... but I'll paste some code here. The main issue I want to solve is this: I have a one-page vertical scroll website with different sections. Since I am so used to working with Nuxt /pages directory I thought it'd be a good idea to keep using the pages directory and to transform the pages into components. But in doing so I am having a difficult time to make those components lazy... I guess I could solve it in using components instead of transformed pages for this and prefixing 'Lazy-' but I was wondering what you think about this ๐Ÿ˜„
<template>
<div class="relative h-[100svh] w-full bg-white">
<main class="absolute inset-0 h-full w-fulloverflow-y-auto px-6">
<component
v-for="(page, idx) in pages"
:is="page.component"
:key="idx"
/>
</main>
</div>
</template>

<script setup>
const pages = [
{ path: '/', component: defineAsyncComponent(() => import('@/pages/landing.vue')) },
{ path: '/volume1', component: defineAsyncComponent(() => import('@/pages/volume1.vue')) },
{ path: '/books', component: defineAsyncComponent(() => import('@/pages/books.vue')) },
{ path: '/about', component: defineAsyncComponent(() => import('@/pages/about.vue')) }
]
</script>
<template>
<div class="relative h-[100svh] w-full bg-white">
<main class="absolute inset-0 h-full w-fulloverflow-y-auto px-6">
<component
v-for="(page, idx) in pages"
:is="page.component"
:key="idx"
/>
</main>
</div>
</template>

<script setup>
const pages = [
{ path: '/', component: defineAsyncComponent(() => import('@/pages/landing.vue')) },
{ path: '/volume1', component: defineAsyncComponent(() => import('@/pages/volume1.vue')) },
{ path: '/books', component: defineAsyncComponent(() => import('@/pages/books.vue')) },
{ path: '/about', component: defineAsyncComponent(() => import('@/pages/about.vue')) }
]
</script>
manniL
manniLโ€ข2mo ago
yeah, it won't work with componen :is You need to use an auto import and it needs to be "statically analyzable"
manniL
manniLโ€ข2mo ago
if you use defineAsyncComponent manually, you can use Vue's lazy hydration directly or wait for https://github.com/nuxt/nuxt/pull/31192
GitHub
feat(nuxt): support lazy hydration macros by Mini-ghost ยท Pull Req...
๐Ÿ”— Linked issue ๐Ÿ“š Description This PR introduces a few macros to provide an explicit import solution for lazy hydration. TODO Macro plugin (LazyHydrationMacroTransformPlugin) Type support Docume...
dataexcess
dataexcessโ€ข2mo ago
do you mean the hydration field in the defineAsyncComponent API ? it seems it's not exposed in nuxt
import { defineAsyncComponent, hydrateOnVisible } from 'vue'

const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})
import { defineAsyncComponent, hydrateOnVisible } from 'vue'

const AsyncComp = defineAsyncComponent({
loader: () => import('./Comp.vue'),
hydrate: hydrateOnVisible()
})
` do you mean importing the Component manually? like we would do without nuxt's auto import? Sorry I'm a bit noobish in these concepts ๐Ÿ˜ฆ
manniL
manniLโ€ข2mo ago
Yes, that should work. The only downside is that you'd have to "remove" the javascript being loaded manually. https://github.com/nuxt/nuxt/pull/31192 should solve both issues actually
GitHub
feat(nuxt): support lazy hydration macros by Mini-ghost ยท Pull Req...
๐Ÿ”— Linked issue ๐Ÿ“š Description This PR introduces a few macros to provide an explicit import solution for lazy hydration. TODO Macro plugin (LazyHydrationMacroTransformPlugin) Type support Docume...
manniL
manniLโ€ข2mo ago
no no, manual imports don't work either. What I mean is that right now, a static string in the template + auto import is necessary. The linked PR offers an explicit solution
dataexcess
dataexcessโ€ข2mo ago
ok so you're saying it basically does not work for dynamic / runtime defined components..? Ah yes - the component needs to be able to be auto imported for it to work - (known as a type by nuxt) I get it now hmmm ok I guess I could checkout on that feature branch... OR i could simply drop the pages directory and use components instead :p
kue
kueโ€ข2w ago
Sorry for the jump in. So, basically the PR is to enable the experimental lazy hydration feature without auto-imports? If I want to enable lazy hydration without that flag, I need to define it with defineAsyncComponent and hydrateOn* method but the js is still loaded?
manniL
manniLโ€ข2w ago
Correct (or use auto imports + SFCs)
kue
kueโ€ข5d ago
Do you have any resource what Nuxt hook to use to strip out the JS and load it when the hydrate function called? I tried to implement the basic with hydrateOnVisible and suspense but the JS is loaded immediately even with artificial delay on the loader, but it actually hydrate on visible. The other quirks is when the Suspense is not wrapped with ClientOnly component, the page will stuck until the async dependency resolved and the fallback not showing at all. I want to keep the template SSR, just like the auto-import lazy hydration (unfortunately that my project is have a bunch of component that live outside components folder, so I decide to disable the auto-import)
kue
kueโ€ข5d ago
I thought that only to strip out the preload/prefetch link on the header when watching your videos. Thank you, now it works like charm! It needs to have separate defineAsyncComponent declaration for the loader, if only use one, it will load the JS right after hydration, not based on hydrate props.
No description
kue
kueโ€ข5d ago
Thank youu!
manniL
manniLโ€ข5d ago
no problem! ๐Ÿ‘ glad it helped ๐Ÿ˜‹

Did you find this page helpful?