perf(nuxt): reduce nuxt island payload (#26569)

This commit is contained in:
Julien Huang 2024-03-30 08:41:46 +01:00 committed by GitHub
parent 41ab12414f
commit 6dcad76a06
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 37 additions and 33 deletions

View File

@ -88,30 +88,32 @@ export default defineComponent({
onMounted(() => { mounted.value = true; teleportKey.value++ }) onMounted(() => { mounted.value = true; teleportKey.value++ })
function setPayload (key: string, result: NuxtIslandResponse) { function setPayload (key: string, result: NuxtIslandResponse) {
const toRevive: Partial<NuxtIslandResponse> = {}
if (result.props) { toRevive.props = result.props }
if (result.slots) { toRevive.slots = result.slots }
if (result.components) { toRevive.components = result.components }
nuxtApp.payload.data[key] = { nuxtApp.payload.data[key] = {
__nuxt_island: { __nuxt_island: {
key, key,
...(import.meta.server && import.meta.prerender) ...(import.meta.server && import.meta.prerender)
? {} ? {}
: { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } }, : { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } },
result: { result: toRevive
props: result.props,
slots: result.slots,
components: result.components
}
}, },
...result ...result
} }
} }
const payloads: Required<Pick<NuxtIslandResponse, 'slots' | 'components'>> = { const payloads: Partial<Pick<NuxtIslandResponse, 'slots' | 'components'>> = {}
slots: {},
components: {}
}
if (instance.vnode.el) { if (instance.vnode.el) {
payloads.slots = toRaw(nuxtApp.payload.data[`${props.name}_${hashId.value}`])?.slots ?? {} const slots = toRaw(nuxtApp.payload.data[`${props.name}_${hashId.value}`])?.slots
payloads.components = toRaw(nuxtApp.payload.data[`${props.name}_${hashId.value}`])?.components ?? {} if (slots) { payloads.slots = slots }
if (selectiveClient) {
const components = toRaw(nuxtApp.payload.data[`${props.name}_${hashId.value}`])?.components
if (components) { payloads.components = components }
}
} }
const ssrHTML = ref<string>('') const ssrHTML = ref<string>('')
@ -137,12 +139,15 @@ export default defineComponent({
} }
} }
return html.replaceAll(SLOT_FALLBACK_RE, (full, slotName) => { if (payloads.slots) {
if (!currentSlots.includes(slotName)) { return html.replaceAll(SLOT_FALLBACK_RE, (full, slotName) => {
return full + (payloads.slots[slotName]?.fallback || '') if (!currentSlots.includes(slotName)) {
} return full + (payloads.slots?.[slotName]?.fallback || '')
return full }
}) return full
})
}
return html
}) })
const cHead = ref<Record<'link' | 'style', Array<Record<string, string>>>>({ link: [], style: [] }) const cHead = ref<Record<'link' | 'style', Array<Record<string, string>>>>({ link: [], style: [] })
@ -256,24 +261,26 @@ export default defineComponent({
teleports.push(createVNode(Teleport, teleports.push(createVNode(Teleport,
// use different selectors for even and odd teleportKey to force trigger the teleport // use different selectors for even and odd teleportKey to force trigger the teleport
{ to: import.meta.client ? `${isKeyOdd ? 'div' : ''}[data-island-uid="${uid.value}"][data-island-slot="${slot}"]` : `uid=${uid.value};slot=${slot}` }, { to: import.meta.client ? `${isKeyOdd ? 'div' : ''}[data-island-uid="${uid.value}"][data-island-slot="${slot}"]` : `uid=${uid.value};slot=${slot}` },
{ default: () => (payloads.slots[slot].props?.length ? payloads.slots[slot].props : [{}]).map((data: any) => slots[slot]?.(data)) }) { default: () => (payloads.slots?.[slot].props?.length ? payloads.slots[slot].props : [{}]).map((data: any) => slots[slot]?.(data)) })
) )
} }
} }
if (selectiveClient) { if (selectiveClient) {
if (import.meta.server) { if (import.meta.server) {
for (const [id, info] of Object.entries(payloads.components ?? {})) { if (payloads.components) {
const { html, slots } = info for (const [id, info] of Object.entries(payloads.components)) {
let replaced = html.replaceAll('data-island-uid', `data-island-uid="${uid.value}"`) const { html, slots } = info
for (const slot in slots) { let replaced = html.replaceAll('data-island-uid', `data-island-uid="${uid.value}"`)
replaced = replaced.replaceAll(`data-island-slot="${slot}">`, full => full + slots[slot]) for (const slot in slots) {
replaced = replaced.replaceAll(`data-island-slot="${slot}">`, full => full + slots[slot])
}
teleports.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
default: () => [createStaticVNode(replaced, 1)]
}))
} }
teleports.push(createVNode(Teleport, { to: `uid=${uid.value};client=${id}` }, {
default: () => [createStaticVNode(replaced, 1)]
}))
} }
} else if (canLoadClientComponent.value) { } else if (canLoadClientComponent.value && payloads.components) {
for (const [id, info] of Object.entries(payloads.components ?? {})) { for (const [id, info] of Object.entries(payloads.components)) {
const { props, slots } = info const { props, slots } = info
const component = components!.get(id)! const component = components!.get(id)!
// use different selectors for even and odd teleportKey to force trigger the teleport // use different selectors for even and odd teleportKey to force trigger the teleport

View File

@ -649,7 +649,7 @@ const SSR_CLIENT_TELEPORT_MARKER = /^uid=([^;]*);client=(.*)$/
const SSR_CLIENT_SLOT_MARKER = /^island-slot=(?:[^;]*);(.*)$/ const SSR_CLIENT_SLOT_MARKER = /^island-slot=(?:[^;]*);(.*)$/
function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['slots'] { function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['slots'] {
if (!ssrContext.islandContext) { return {} } if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.slots).length) { return undefined }
const response: NuxtIslandResponse['slots'] = {} const response: NuxtIslandResponse['slots'] = {}
for (const slot in ssrContext.islandContext.slots) { for (const slot in ssrContext.islandContext.slots) {
response[slot] = { response[slot] = {
@ -661,7 +661,7 @@ function getSlotIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse[
} }
function getClientIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['components'] { function getClientIslandResponse (ssrContext: NuxtSSRContext): NuxtIslandResponse['components'] {
if (!ssrContext.islandContext) { return {} } if (!ssrContext.islandContext || !Object.keys(ssrContext.islandContext.components).length) { return undefined }
const response: NuxtIslandResponse['components'] = {} const response: NuxtIslandResponse['components'] = {}
for (const clientUid in ssrContext.islandContext.components) { for (const clientUid in ssrContext.islandContext.components) {

View File

@ -1968,14 +1968,12 @@ describe('component islands', () => {
expect(result).toMatchInlineSnapshot(` expect(result).toMatchInlineSnapshot(`
{ {
"components": {},
"head": { "head": {
"link": [], "link": [],
"style": [], "style": [],
}, },
"html": "<pre data-island-uid> Route: /foo "html": "<pre data-island-uid> Route: /foo
</pre>", </pre>",
"slots": {},
"state": {}, "state": {},
} }
`) `)
@ -1993,7 +1991,6 @@ describe('component islands', () => {
result.html = result.html.replaceAll(/ (data-island-uid|data-island-component)="([^"]*)"/g, '') result.html = result.html.replaceAll(/ (data-island-uid|data-island-component)="([^"]*)"/g, '')
expect(result).toMatchInlineSnapshot(` expect(result).toMatchInlineSnapshot(`
{ {
"components": {},
"head": { "head": {
"link": [], "link": [],
"style": [], "style": [],