2024-03-06 15:26:19 +00:00
|
|
|
import type { Component, InjectionKey } from 'vue'
|
|
|
|
import { Teleport, defineComponent, h, inject, provide } from 'vue'
|
2023-12-19 12:21:29 +00:00
|
|
|
import { useNuxtApp } from '../nuxt'
|
|
|
|
// @ts-expect-error virtual file
|
|
|
|
import { paths } from '#build/components-chunk'
|
|
|
|
|
|
|
|
type ExtendedComponent = Component & {
|
|
|
|
__file: string,
|
|
|
|
__name: string
|
|
|
|
}
|
|
|
|
|
2024-03-06 15:26:19 +00:00
|
|
|
export const NuxtTeleportIslandSymbol = Symbol('NuxtTeleportIslandComponent') as InjectionKey<false | string>
|
|
|
|
|
2023-12-19 12:21:29 +00:00
|
|
|
/**
|
|
|
|
* component only used with componentsIsland
|
|
|
|
* this teleport the component in SSR only if it needs to be hydrated on client
|
|
|
|
*/
|
2024-02-21 21:20:55 +00:00
|
|
|
/* @__PURE__ */
|
2023-12-19 12:21:29 +00:00
|
|
|
export default defineComponent({
|
2024-01-16 16:33:45 +00:00
|
|
|
name: 'NuxtTeleportIslandComponent',
|
2023-12-19 12:21:29 +00:00
|
|
|
props: {
|
|
|
|
to: {
|
|
|
|
type: String,
|
|
|
|
required: true
|
|
|
|
},
|
|
|
|
nuxtClient: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
/**
|
|
|
|
* ONLY used in dev mode since we use build:manifest result in production
|
|
|
|
* do not pass any value in production
|
|
|
|
*/
|
|
|
|
rootDir: {
|
|
|
|
type: String,
|
|
|
|
default: null
|
|
|
|
}
|
|
|
|
},
|
|
|
|
setup (props, { slots }) {
|
2024-01-16 13:22:50 +00:00
|
|
|
const nuxtApp = useNuxtApp()
|
2023-12-19 12:21:29 +00:00
|
|
|
|
2024-03-06 15:26:19 +00:00
|
|
|
// if there's already a teleport parent, we don't need to teleport or to render the wrapped component client side
|
|
|
|
if (!nuxtApp.ssrContext?.islandContext || !props.nuxtClient || inject(NuxtTeleportIslandSymbol, false)) { return () => slots.default?.() }
|
2024-01-16 13:22:50 +00:00
|
|
|
|
2024-03-06 15:26:19 +00:00
|
|
|
provide(NuxtTeleportIslandSymbol, props.to)
|
2024-01-16 13:22:50 +00:00
|
|
|
const islandContext = nuxtApp.ssrContext!.islandContext!
|
2023-12-19 12:21:29 +00:00
|
|
|
|
|
|
|
return () => {
|
|
|
|
const slot = slots.default!()[0]
|
|
|
|
const slotType = (slot.type as ExtendedComponent)
|
|
|
|
const name = (slotType.__name || slotType.name) as string
|
|
|
|
|
2024-01-16 13:22:50 +00:00
|
|
|
islandContext.components[props.to] = {
|
|
|
|
chunk: import.meta.dev ? '_nuxt/' + paths[name] : paths[name],
|
|
|
|
props: slot.props || {}
|
|
|
|
}
|
2023-12-19 12:21:29 +00:00
|
|
|
|
|
|
|
return [h('div', {
|
|
|
|
style: 'display: contents;',
|
2024-01-16 13:22:50 +00:00
|
|
|
'data-island-uid': '',
|
2024-01-16 16:33:45 +00:00
|
|
|
'data-island-component': props.to
|
2023-12-19 12:21:29 +00:00
|
|
|
}, []), h(Teleport, { to: props.to }, slot)]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|