mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-26 07:32:01 +00:00
perf(nuxt): prepopulate island payloads from rendered html (#22049)
Co-authored-by: Julien Huang <julien.huang@outlook.fr>
This commit is contained in:
parent
08acfb749d
commit
dcef9d94cd
@ -48,7 +48,33 @@ export default defineComponent({
|
|||||||
const mounted = ref(false)
|
const mounted = ref(false)
|
||||||
onMounted(() => { mounted.value = true })
|
onMounted(() => { mounted.value = true })
|
||||||
|
|
||||||
const ssrHTML = ref<string>(process.client ? getFragmentHTML(instance.vnode?.el ?? null).join('') ?? '<div></div>' : '<div></div>')
|
function setPayload (key: string, result: NuxtIslandResponse) {
|
||||||
|
nuxtApp.payload.data[key] = {
|
||||||
|
__nuxt_island: {
|
||||||
|
key,
|
||||||
|
...(process.server && process.env.prerender)
|
||||||
|
? {}
|
||||||
|
: { params: { ...props.context, props: props.props ? JSON.stringify(props.props) : undefined } }
|
||||||
|
},
|
||||||
|
...result
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const ssrHTML = ref('<div></div>')
|
||||||
|
if (process.client) {
|
||||||
|
const renderedHTML = getFragmentHTML(instance.vnode?.el ?? null).join('')
|
||||||
|
if (renderedHTML && nuxtApp.isHydrating) {
|
||||||
|
setPayload(`${props.name}_${hashId.value}`, {
|
||||||
|
html: getFragmentHTML(instance.vnode?.el ?? null, true).join(''),
|
||||||
|
state: {},
|
||||||
|
head: {
|
||||||
|
link: [],
|
||||||
|
style: []
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
ssrHTML.value = renderedHTML ?? '<div></div>'
|
||||||
|
}
|
||||||
const slotProps = computed(() => getSlotProps(ssrHTML.value))
|
const slotProps = computed(() => getSlotProps(ssrHTML.value))
|
||||||
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID())
|
const uid = ref<string>(ssrHTML.value.match(SSR_UID_RE)?.[1] ?? randomUUID())
|
||||||
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
|
const availableSlots = computed(() => [...ssrHTML.value.matchAll(SLOTNAME_RE)].map(m => m[1]))
|
||||||
@ -91,20 +117,7 @@ export default defineComponent({
|
|||||||
appendResponseHeader(event, 'x-nitro-prerender', hints)
|
appendResponseHeader(event, 'x-nitro-prerender', hints)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
nuxtApp.payload.data[key] = {
|
setPayload(key, result)
|
||||||
__nuxt_island: {
|
|
||||||
key,
|
|
||||||
...(process.server && process.env.prerender)
|
|
||||||
? {}
|
|
||||||
: {
|
|
||||||
params: {
|
|
||||||
...props.context,
|
|
||||||
props: props.props ? JSON.stringify(props.props) : undefined
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
...result
|
|
||||||
}
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
const key = ref(0)
|
const key = ref(0)
|
||||||
|
@ -99,25 +99,42 @@ export function vforToArray (source: any): any[] {
|
|||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getFragmentHTML (element: RendererNode | null) {
|
/**
|
||||||
|
* Retrieve the HTML content from an element
|
||||||
|
* Handles `<!--[-->` Fragment elements
|
||||||
|
*
|
||||||
|
* @param element the element to retrieve the HTML
|
||||||
|
* @param withoutSlots purge all slots from the HTML string retrieved
|
||||||
|
* @returns {string[]} An array of string which represent the content of each element. Use `.join('')` to retrieve a component vnode.el HTML
|
||||||
|
*/
|
||||||
|
export function getFragmentHTML (element: RendererNode | null, withoutSlots = false) {
|
||||||
if (element) {
|
if (element) {
|
||||||
if (element.nodeName === '#comment' && element.nodeValue === '[') {
|
if (element.nodeName === '#comment' && element.nodeValue === '[') {
|
||||||
return getFragmentChildren(element)
|
return getFragmentChildren(element, [], withoutSlots)
|
||||||
|
}
|
||||||
|
if (withoutSlots) {
|
||||||
|
const clone = element.cloneNode(true)
|
||||||
|
clone.querySelectorAll('[nuxt-ssr-slot-name]').forEach((n: Element) => { n.innerHTML = '' })
|
||||||
|
return [clone.outerHTML]
|
||||||
}
|
}
|
||||||
return [element.outerHTML]
|
return [element.outerHTML]
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
function getFragmentChildren (element: RendererNode | null, blocks: string[] = []) {
|
function getFragmentChildren (element: RendererNode | null, blocks: string[] = [], withoutSlots = false) {
|
||||||
if (element && element.nodeName) {
|
if (element && element.nodeName) {
|
||||||
if (isEndFragment(element)) {
|
if (isEndFragment(element)) {
|
||||||
return blocks
|
return blocks
|
||||||
} else if (!isStartFragment(element)) {
|
} else if (!isStartFragment(element)) {
|
||||||
blocks.push(element.outerHTML)
|
const clone = element.cloneNode(true) as Element
|
||||||
|
if (withoutSlots) {
|
||||||
|
clone.querySelectorAll('[nuxt-ssr-slot-name]').forEach((n) => { n.innerHTML = '' })
|
||||||
|
}
|
||||||
|
blocks.push(clone.outerHTML)
|
||||||
}
|
}
|
||||||
|
|
||||||
getFragmentChildren(element.nextSibling, blocks)
|
getFragmentChildren(element.nextSibling, blocks, withoutSlots)
|
||||||
}
|
}
|
||||||
return blocks
|
return blocks
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user