mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-21 21:25:11 +00:00
fix(nuxt): allow islands to manipulate head client-side (#29186)
This commit is contained in:
parent
1a659b326a
commit
ca65f150b3
@ -1,9 +1,9 @@
|
||||
import type { Component, PropType, VNode } from 'vue'
|
||||
import { Fragment, Teleport, computed, createStaticVNode, createVNode, defineComponent, getCurrentInstance, h, nextTick, onMounted, ref, toRaw, watch, withMemo } from 'vue'
|
||||
import { Fragment, Teleport, computed, createStaticVNode, createVNode, defineComponent, getCurrentInstance, h, nextTick, onBeforeUnmount, onMounted, ref, toRaw, watch, withMemo } from 'vue'
|
||||
import { debounce } from 'perfect-debounce'
|
||||
import { hash } from 'ohash'
|
||||
import { appendResponseHeader } from 'h3'
|
||||
import { injectHead } from '@unhead/vue'
|
||||
import { type ActiveHeadEntry, type Head, injectHead } from '@unhead/vue'
|
||||
import { randomUUID } from 'uncrypto'
|
||||
import { joinURL, withQuery } from 'ufo'
|
||||
import type { FetchResponse } from 'ofetch'
|
||||
@ -90,11 +90,13 @@ export default defineComponent({
|
||||
const instance = getCurrentInstance()!
|
||||
const event = useRequestEvent()
|
||||
|
||||
let activeHead: ActiveHeadEntry<Head>
|
||||
|
||||
// TODO: remove use of `$fetch.raw` when nitro 503 issues on windows dev server are resolved
|
||||
const eventFetch = import.meta.server ? event!.fetch : import.meta.dev ? $fetch.raw : globalThis.fetch
|
||||
const mounted = ref(false)
|
||||
onMounted(() => { mounted.value = true; teleportKey.value++ })
|
||||
|
||||
onBeforeUnmount(() => { if (activeHead) { activeHead.dispose() } })
|
||||
function setPayload (key: string, result: NuxtIslandResponse) {
|
||||
const toRevive: Partial<NuxtIslandResponse> = {}
|
||||
if (result.props) { toRevive.props = result.props }
|
||||
@ -215,6 +217,14 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
if (res?.head) {
|
||||
if (activeHead) {
|
||||
activeHead.patch(res.head)
|
||||
} else {
|
||||
activeHead = head.push(res.head)
|
||||
}
|
||||
}
|
||||
|
||||
if (import.meta.client) {
|
||||
// must await next tick for Teleport to work correctly with static node re-rendering
|
||||
nextTick(() => {
|
||||
@ -250,14 +260,6 @@ export default defineComponent({
|
||||
await loadComponents(props.source, payloads.components)
|
||||
}
|
||||
|
||||
if (import.meta.server || nuxtApp.isHydrating) {
|
||||
// re-push head into active head instance
|
||||
const responseHead = (nuxtApp.payload.data[`${props.name}_${hashId.value}`] as NuxtIslandResponse)?.head
|
||||
if (responseHead) {
|
||||
head.push(responseHead)
|
||||
}
|
||||
}
|
||||
|
||||
return (_ctx: any, _cache: any) => {
|
||||
if (!html.value || error.value) {
|
||||
return [slots.fallback?.({ error: error.value }) ?? createVNode('div')]
|
||||
|
@ -1984,6 +1984,15 @@ describe('server components/islands', () => {
|
||||
expect(html).toContain('<meta name="author" content="Nuxt">')
|
||||
})
|
||||
|
||||
it('/server-page - client side navigation', async () => {
|
||||
const { page } = await renderPage('/')
|
||||
await page.getByText('to server page').click()
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
expect(await page.innerHTML('head')).toContain('<meta name="author" content="Nuxt">')
|
||||
await page.close()
|
||||
})
|
||||
|
||||
it.skipIf(isDev)('should allow server-only components to set prerender hints', async () => {
|
||||
// @ts-expect-error ssssh! untyped secret property
|
||||
const publicDir = useTestContext().nuxt._nitro.options.output.publicDir
|
||||
|
Loading…
Reference in New Issue
Block a user