diff --git a/packages/nuxt/src/app/components/TeleportIfClient.ts b/packages/nuxt/src/app/components/TeleportIfClient.ts
index 8974b4088b..c9439583e1 100644
--- a/packages/nuxt/src/app/components/TeleportIfClient.ts
+++ b/packages/nuxt/src/app/components/TeleportIfClient.ts
@@ -1,6 +1,6 @@
+import { relative } from 'node:path'
import { Teleport, defineComponent, h } from 'vue'
import { useNuxtApp } from '#app'
-import { relative } from 'path'
/**
* component only used with componentsIsland
@@ -24,7 +24,6 @@ export default defineComponent({
}
},
setup (props, { slots }) {
-
const app = useNuxtApp()
const islandContext = app.ssrContext!.islandContext
@@ -33,14 +32,13 @@ export default defineComponent({
console.log(slot)
if (process.dev) {
console.log(app)
- const path = '__nuxt/' + relative(props.rootDir, slot.type.__file)
+ const path = '_nuxt/' + relative(props.rootDir, slot.type.__file)
islandContext.chunks[slot.type.__name] = path
}
islandContext.propsData[props.to] = slot.props || {}
// todo set prop in payload
return () => {
-
if (props.nuxtClient) {
return [h('div', {
style: 'display: contents;',
diff --git a/packages/nuxt/src/app/components/nuxt-island.ts b/packages/nuxt/src/app/components/nuxt-island.ts
index 5b040dacfa..d26ab00bf3 100644
--- a/packages/nuxt/src/app/components/nuxt-island.ts
+++ b/packages/nuxt/src/app/components/nuxt-island.ts
@@ -1,3 +1,4 @@
+import type { Component } from 'vue'
import { Fragment, Teleport, computed, createStaticVNode, createVNode, defineComponent, getCurrentInstance, h, nextTick, onMounted, ref, watch } from 'vue'
import { debounce } from 'perfect-debounce'
import { hash } from 'ohash'
@@ -6,6 +7,7 @@ import { useHead } from '@unhead/vue'
import { randomUUID } from 'uncrypto'
import { joinURL, withQuery } from 'ufo'
import type { FetchResponse } from 'ofetch'
+import { join } from 'pathe'
// eslint-disable-next-line import/no-restricted-paths
import type { NuxtIslandResponse } from '../../core/runtime/nitro/renderer'
@@ -24,18 +26,17 @@ const SLOTNAME_RE = /nuxt-ssr-slot-name="([^"]*)"/g
const SLOT_FALLBACK_RE = /
]*><\/div>(((?!
]*>)[\s\S])*)
]*><\/div>/g
let id = 0
-const getId = process.client ? () => (id++).toString() : randomUUID
-const components = process.client ? new Map
() : undefined
+const getId = import.meta.client ? () => (id++).toString() : randomUUID
+const components = import.meta.client ? new Map() : undefined
-async function loadComponents (paths: Record) {
+async function loadComponents (source = '/', paths: Record) {
const promises = []
- debugger
for (const component in paths) {
if (!(components!.has(component))) {
promises.push((async () => {
- const c = await import('http://localhost:3000/__nuxt/components/SugarCounter.vue')
- debugger
+ const chunkSource = join(source, paths[component])
+ const c = await import(chunkSource)
components!.set(component, c.default ?? c)
})())
}
@@ -109,9 +110,24 @@ export default defineComponent({
const uid = ref(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID())
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
+ // no need for reactivity
+ let interactiveComponentsList: Record> = {}
+
const html = computed(() => {
const currentSlots = Object.keys(slots)
- return ssrHTML.value.replace(SLOT_FALLBACK_RE, (full, slotName, content) => {
+ let html = ssrHTML.value
+ if (process.client) {
+ const el = document.createElement('html')
+ el.innerHTML = html
+ Object.entries(interactiveComponentsList).forEach(([id]) => {
+ const interactiveWrapper = el.querySelector(`[nuxt-ssr-client="${id}"]`)
+ if (interactiveWrapper) {
+ interactiveWrapper.innerHTML = ''
+ }
+ })
+ html = el.innerHTML
+ }
+ return html.replace(SLOT_FALLBACK_RE, (full, slotName, content) => {
// remove fallback to insert slots
if (currentSlots.includes(slotName)) {
return ''
@@ -120,8 +136,6 @@ export default defineComponent({
})
})
- // no need for reactivity
- let interactiveComponentsList = {}
function setUid () {
uid.value = ssrHTML.value.match(SSR_UID_RE)?.[1] ?? getId() as string
}
@@ -176,16 +190,16 @@ export default defineComponent({
// must await next tick for Teleport to work correctly with static node re-rendering
await nextTick()
}
+
+ if (process.client) {
+ await loadComponents(props.source, res.chunks)
+ interactiveComponentsList = res.props
+ }
+
setUid()
} catch (e) {
error.value = e
}
- setUid()
-
- if (process.client) {
- await loadComponents(res.chunks)
- interactiveComponentsList = res.props
- }
}
if (import.meta.hot) {
@@ -221,10 +235,11 @@ export default defineComponent({
}
}
if (process.client && html.value.includes('nuxt-ssr-client') && mounted.value) {
-
- for (const id in interactiveComponentsList) {
+ for (const [id, props] of Object.entries(interactiveComponentsList)) {
const vnode = createVNode(Teleport, { to: `[nuxt-ssr-component-uid='${uid.value}'] [nuxt-ssr-client="${id}"]` }, {
- default: () => [h(components!.get(id.split('-')[0]), interactiveComponentsList[id])]
+ default: () => {
+ return [h(components!.get(id.split('-')[0])!, props)]
+ }
})
nodes.push(vnode)
}
diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts
index 626b95858a..c6bd628716 100644
--- a/packages/nuxt/src/core/runtime/nitro/renderer.ts
+++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts
@@ -424,7 +424,7 @@ export default defineRenderHandler(async (event): Promise