mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-18 17:35:57 +00:00
perf(nuxt): remove code duplication in client-only (#30460)
This commit is contained in:
parent
2438130f6b
commit
8b8a731dff
@ -1,12 +1,14 @@
|
||||
import { cloneVNode, createElementBlock, createStaticVNode, defineComponent, getCurrentInstance, h, onMounted, provide, ref } from 'vue'
|
||||
import { cloneVNode, createElementBlock, defineComponent, getCurrentInstance, h, onMounted, provide, ref } from 'vue'
|
||||
import type { ComponentInternalInstance, ComponentOptions, InjectionKey } from 'vue'
|
||||
import { isPromise } from '@vue/shared'
|
||||
import { useNuxtApp } from '../nuxt'
|
||||
import { getFragmentHTML } from './utils'
|
||||
import ServerPlaceholder from './server-placeholder'
|
||||
import { elToStaticVNode } from './utils'
|
||||
|
||||
export const clientOnlySymbol: InjectionKey<boolean> = Symbol.for('nuxt:client-only')
|
||||
|
||||
const STATIC_DIV = '<div></div>'
|
||||
|
||||
export default defineComponent({
|
||||
name: 'ClientOnly',
|
||||
inheritAttrs: false,
|
||||
@ -54,16 +56,14 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
|
||||
return (res.children === null || typeof res.children === 'string')
|
||||
? cloneVNode(res)
|
||||
: h(res)
|
||||
} else {
|
||||
const fragment = getFragmentHTML(ctx._.vnode.el ?? null) ?? ['<div></div>']
|
||||
return createStaticVNode(fragment.join(''), fragment.length)
|
||||
}
|
||||
return elToStaticVNode(ctx._.vnode.el, STATIC_DIV)
|
||||
}
|
||||
} else if (clone.template) {
|
||||
// handle runtime-compiler template
|
||||
clone.template = `
|
||||
<template v-if="mounted$">${component.template}</template>
|
||||
<template v-else><div></div></template>
|
||||
<template v-else>${STATIC_DIV}</template>
|
||||
`
|
||||
}
|
||||
|
||||
@ -105,10 +105,8 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
|
||||
return (res.children === null || typeof res.children === 'string')
|
||||
? cloneVNode(res)
|
||||
: h(res)
|
||||
} else {
|
||||
const fragment = getFragmentHTML(instance?.vnode.el ?? null) ?? ['<div></div>']
|
||||
return createStaticVNode(fragment.join(''), fragment.length)
|
||||
}
|
||||
return elToStaticVNode(instance?.vnode.el, STATIC_DIV)
|
||||
}
|
||||
})
|
||||
} else {
|
||||
@ -117,8 +115,7 @@ export function createClientOnly<T extends ComponentOptions> (component: T) {
|
||||
if (mounted$.value) {
|
||||
return h(setupState(...args), ctx.attrs)
|
||||
}
|
||||
const fragment = getFragmentHTML(instance?.vnode.el ?? null) ?? ['<div></div>']
|
||||
return createStaticVNode(fragment.join(''), fragment.length)
|
||||
return elToStaticVNode(instance?.vnode.el, STATIC_DIV)
|
||||
}
|
||||
}
|
||||
return Object.assign(setupState, { mounted$ })
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { h } from 'vue'
|
||||
import type { Component, RendererNode } from 'vue'
|
||||
import { createStaticVNode, h } from 'vue'
|
||||
import type { Component, RendererNode, VNode } from 'vue'
|
||||
// eslint-disable-next-line
|
||||
import { isString, isPromise, isArray, isObject } from '@vue/shared'
|
||||
import type { RouteLocationNormalized } from 'vue-router'
|
||||
@ -117,9 +117,9 @@ export function vforToArray (source: any): any[] {
|
||||
* 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
|
||||
* @returns {string[]|undefined} 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): string[] | null {
|
||||
export function getFragmentHTML (element: RendererNode | null, withoutSlots = false): string[] | undefined {
|
||||
if (element) {
|
||||
if (element.nodeName === '#comment' && element.nodeValue === '[') {
|
||||
return getFragmentChildren(element, [], withoutSlots)
|
||||
@ -131,7 +131,6 @@ export function getFragmentHTML (element: RendererNode | null, withoutSlots = fa
|
||||
}
|
||||
return [element.outerHTML]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function getFragmentChildren (element: RendererNode | null, blocks: string[] = [], withoutSlots = false) {
|
||||
@ -151,6 +150,20 @@ function getFragmentChildren (element: RendererNode | null, blocks: string[] = [
|
||||
return blocks
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a static vnode from an element
|
||||
* Default to a div if the element is not found and if a fallback is not provided
|
||||
* @param el renderer node retrieved from the component internal instance
|
||||
* @param staticNodeFallback fallback string to use if the element is not found. Must be a valid HTML string
|
||||
*/
|
||||
export function elToStaticVNode (el: RendererNode | null, staticNodeFallback?: string): VNode {
|
||||
const fragment: string[] | undefined = el ? getFragmentHTML(el) : staticNodeFallback ? [staticNodeFallback] : undefined
|
||||
if (fragment) {
|
||||
return createStaticVNode(fragment.join(''), fragment.length)
|
||||
}
|
||||
return h('div')
|
||||
}
|
||||
|
||||
function isStartFragment (element: RendererNode) {
|
||||
return element.nodeName === '#comment' && element.nodeValue === '['
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user