diff --git a/packages/nuxt/src/app/components/TeleportIfClient.ts b/packages/nuxt/src/app/components/TeleportIfClient.ts index e5fa6fa529..7a10f10bde 100644 --- a/packages/nuxt/src/app/components/TeleportIfClient.ts +++ b/packages/nuxt/src/app/components/TeleportIfClient.ts @@ -1,9 +1,15 @@ import { relative } from 'node:path' +import type { Component } from 'vue' import { Teleport, defineComponent, h } from 'vue' import { useNuxtApp } from '#app' // @ts-expect-error virtual file import { paths } from '#build/components-chunk' +type ExtendedComponent = Component & { + __file: string, + __name: string +} + /** * component only used with componentsIsland * this teleport the component in SSR only if @@ -34,12 +40,14 @@ export default defineComponent({ const islandContext = app.ssrContext!.islandContext! const slot = slots.default!()[0] - if (process.dev) { - const path = '_nuxt/' + relative(props.rootDir, slot.type.__file) + const slotType = (slot.type as ExtendedComponent) - islandContext.chunks[slot.type.__name] = path - } else { - islandContext.chunks[slot.type.__name] = paths[slot.type.__name] + if (process.dev) { + const path = '_nuxt/' + relative(props.rootDir, slotType.__file) + + islandContext.chunks[slotType.__name] = path + } else { + islandContext.chunks[slotType.__name] = paths[slotType.__name] } // todo chunk path in production islandContext.propsData[props.to] = slot.props || {} diff --git a/packages/nuxt/src/app/components/nuxt-island.ts b/packages/nuxt/src/app/components/nuxt-island.ts index a7df8860d5..1d150d4d04 100644 --- a/packages/nuxt/src/app/components/nuxt-island.ts +++ b/packages/nuxt/src/app/components/nuxt-island.ts @@ -101,7 +101,8 @@ export default defineComponent({ style: [] }, chunks: {}, - props: {} + props: {}, + teleports: {} }) } ssrHTML.value = renderedHTML @@ -111,13 +112,14 @@ export default defineComponent({ const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1])) // no need for reactivity + // eslint-disable-next-line vue/no-setup-props-destructure let interactiveProps: Record> = process.client && nuxtApp.isHydrating ? toRaw(nuxtApp.payload.data[`${props.name}_${hashId.value}_interactive`].props) : {} const interactiveChunksList = process.client && nuxtApp.isHydrating ? nuxtApp.payload.data[`${props.name}_${hashId.value}_interactive`].chunks : {} -let interactiveTeleports = {} + let interactiveTeleports: Record = {} const html = computed(() => { const currentSlots = Object.keys(slots) - let html = ssrHTML.value - + const html = ssrHTML.value + return html.replace(SLOT_FALLBACK_RE, (full, slotName, content) => { // remove fallback to insert slots if (currentSlots.includes(slotName)) { @@ -189,8 +191,8 @@ let interactiveTeleports = {} if (process.client) { await loadComponents(props.source, res.chunks) interactiveProps = res.props - } else { - interactiveTeleports = res.teleports ||{} + } else { + interactiveTeleports = res.teleports || {} } setUid() @@ -236,15 +238,14 @@ let interactiveTeleports = {} } if (process.server) { for (const [id, html] of Object.entries(interactiveTeleports)) { - - nodes.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}`}, { - default: () => [createStaticVNode(html, 1)] - + nodes.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, { + default: () => [createStaticVNode(html, 1)] })) } } - if (process.client && html.value.includes('nuxt-ssr-client') ) { + if (process.client && html.value.includes('nuxt-ssr-client')) { for (const [id, props] of Object.entries(interactiveProps)) { + // @ts-expect-error _ is the components default export in build chunks const component = components!.get(id.split('-')[0])!._ ?? components!.get(id.split('-')[0])! const vnode = createVNode(Teleport, { to: `[nuxt-ssr-component-uid='${uid.value}'] [nuxt-ssr-client="${id}"]` }, { default: () => { diff --git a/packages/nuxt/src/components/islandsTransform.ts b/packages/nuxt/src/components/islandsTransform.ts index 07ed7ac52b..9b6dcbdbd3 100644 --- a/packages/nuxt/src/components/islandsTransform.ts +++ b/packages/nuxt/src/components/islandsTransform.ts @@ -134,17 +134,21 @@ export const componentsChunkPlugin = createUnplugin((options: ServerOnlyComponen config.build = config.build || {} config.build.rollupOptions = config.build.rollupOptions || {} config.build.rollupOptions.output = config.build.rollupOptions.output || {} - if (Array.isArray(config.build.rollupOptions.output)) { - } else { - config.build.rollupOptions.output.manualChunks = (id, { getModuleIds, getModuleInfo }) => { - if (components.some(c => c.filePath === parseURL(decodeURIComponent(pathToFileURL(id).href)).pathname)) { - return basename(id) - } + const componentManualChunk = (id: string) => { + if (components.some(c => c.filePath === parseURL(decodeURIComponent(pathToFileURL(id).href)).pathname)) { + return basename(id) } } + if (Array.isArray(config.build.rollupOptions.output)) { + config.build.rollupOptions.output.forEach((output) => { + output.manualChunks = componentManualChunk + }) + } else { + config.build.rollupOptions.output.manualChunks = componentManualChunk + } }, - generateBundle (opts, bundle) { + generateBundle (_opts, bundle) { const components = options.getComponents() const componentsChunks = Object.entries(bundle).filter(([_chunkPath, chunkInfo]) => { if (chunkInfo.type !== 'chunk') { return false } @@ -162,8 +166,8 @@ export const componentsChunkPlugin = createUnplugin((options: ServerOnlyComponen }) }) - fs.writeFileSync(join(options.nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = /* #__PURE__ */ ${JSON.stringify(componentsChunks.reduce((acc, [chunkPath, chunkInfo]) => { - if (chunkInfo.type && chunkInfo.name && chunkInfo.exports && chunkInfo.exports.length > 0) { return Object.assign(acc, { [withoutClientSuffixAndExtension(chunkInfo.name)]: chunkPath }) } + fs.writeFileSync(join(options.nuxt.options.buildDir, 'components-chunk.mjs'), `export const paths = ${JSON.stringify(componentsChunks.reduce((acc, [chunkPath, chunkInfo]) => { + if (chunkInfo.type === 'chunk' && chunkInfo.name && chunkInfo.exports.length > 0) { return Object.assign(acc, { [withoutClientSuffixAndExtension(chunkInfo.name)]: chunkPath }) } return acc }, {}))}`) } diff --git a/packages/nuxt/src/core/nuxt.ts b/packages/nuxt/src/core/nuxt.ts index 3b5c7896f3..b703f64944 100644 --- a/packages/nuxt/src/core/nuxt.ts +++ b/packages/nuxt/src/core/nuxt.ts @@ -279,10 +279,6 @@ async function initNuxt (nuxt: Nuxt) { priority: 10, // built-in that we do not expect the user to override filePath: resolve(nuxt.options.appDir, 'components/nuxt-island') }) - - nuxt.hook('build:manifest', (manifest) => { - debugger - }) } // Add experimental cross-origin prefetch support using Speculation Rules API diff --git a/packages/nuxt/src/core/runtime/nitro/renderer.ts b/packages/nuxt/src/core/runtime/nitro/renderer.ts index 27546aa18f..781e78617c 100644 --- a/packages/nuxt/src/core/runtime/nitro/renderer.ts +++ b/packages/nuxt/src/core/runtime/nitro/renderer.ts @@ -426,14 +426,14 @@ export default defineRenderHandler(async (event): Promise]*>((?!nuxt-ssr-client="${clientId}"|nuxt-ssr-component-uid)[\\s\\S])*
]*nuxt-ssr-client="${clientId}"[^>]*>`), (full) => { return full + teleports[key] }) - console.log(html, 'HTMLLLLLLLL') } return html }