mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-22 05:35:13 +00:00
fix(nuxt): add parent scopeId
to server components (#27497)
This commit is contained in:
parent
cd95d99704
commit
9655ce6f62
@ -1,4 +1,4 @@
|
|||||||
import type { Component } from 'vue'
|
import type { Component, PropType } 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, onMounted, ref, toRaw, watch, withMemo } from 'vue'
|
||||||
import { debounce } from 'perfect-debounce'
|
import { debounce } from 'perfect-debounce'
|
||||||
import { hash } from 'ohash'
|
import { hash } from 'ohash'
|
||||||
@ -59,6 +59,10 @@ export default defineComponent({
|
|||||||
type: Object,
|
type: Object,
|
||||||
default: () => ({}),
|
default: () => ({}),
|
||||||
},
|
},
|
||||||
|
scopeId: {
|
||||||
|
type: String as PropType<string | undefined | null>,
|
||||||
|
default: () => undefined,
|
||||||
|
},
|
||||||
source: {
|
source: {
|
||||||
type: String,
|
type: String,
|
||||||
default: () => undefined,
|
default: () => undefined,
|
||||||
@ -131,6 +135,10 @@ export default defineComponent({
|
|||||||
const currentSlots = Object.keys(slots)
|
const currentSlots = Object.keys(slots)
|
||||||
let html = ssrHTML.value
|
let html = ssrHTML.value
|
||||||
|
|
||||||
|
if (props.scopeId) {
|
||||||
|
html = html.replace(/^<[^> ]*/, full => full + ' ' + props.scopeId)
|
||||||
|
}
|
||||||
|
|
||||||
if (import.meta.client && !canLoadClientComponent.value) {
|
if (import.meta.client && !canLoadClientComponent.value) {
|
||||||
for (const [key, value] of Object.entries(payloads.components || {})) {
|
for (const [key, value] of Object.entries(payloads.components || {})) {
|
||||||
html = html.replace(new RegExp(` data-island-uid="${uid.value}" data-island-component="${key}"[^>]*>`), (full) => {
|
html = html.replace(new RegExp(` data-island-uid="${uid.value}" data-island-component="${key}"[^>]*>`), (full) => {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { defineComponent, h, ref } from 'vue'
|
import { defineComponent, getCurrentInstance, h, ref } from 'vue'
|
||||||
import NuxtIsland from '#app/components/nuxt-island'
|
import NuxtIsland from '#app/components/nuxt-island'
|
||||||
import { useRoute } from '#app/composables/router'
|
import { useRoute } from '#app/composables/router'
|
||||||
import { isPrerendered } from '#app/composables/payload'
|
import { isPrerendered } from '#app/composables/payload'
|
||||||
@ -11,6 +11,7 @@ export const createServerComponent = (name: string) => {
|
|||||||
props: { lazy: Boolean },
|
props: { lazy: Boolean },
|
||||||
emits: ['error'],
|
emits: ['error'],
|
||||||
setup (props, { attrs, slots, expose, emit }) {
|
setup (props, { attrs, slots, expose, emit }) {
|
||||||
|
const vm = getCurrentInstance()
|
||||||
const islandRef = ref<null | typeof NuxtIsland>(null)
|
const islandRef = ref<null | typeof NuxtIsland>(null)
|
||||||
|
|
||||||
expose({
|
expose({
|
||||||
@ -22,6 +23,7 @@ export const createServerComponent = (name: string) => {
|
|||||||
name,
|
name,
|
||||||
lazy: props.lazy,
|
lazy: props.lazy,
|
||||||
props: attrs,
|
props: attrs,
|
||||||
|
scopeId: vm?.vnode.scopeId,
|
||||||
ref: islandRef,
|
ref: islandRef,
|
||||||
onError: (err) => {
|
onError: (err) => {
|
||||||
emit('error', err)
|
emit('error', err)
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { beforeEach } from 'node:test'
|
import { beforeEach } from 'node:test'
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
import { h, nextTick } from 'vue'
|
import { defineComponent, h, nextTick, popScopeId, pushScopeId } from 'vue'
|
||||||
import { mountSuspended } from '@nuxt/test-utils/runtime'
|
import { mountSuspended } from '@nuxt/test-utils/runtime'
|
||||||
import { createServerComponent } from '../../packages/nuxt/src/components/runtime/server-component'
|
import { createServerComponent } from '../../packages/nuxt/src/components/runtime/server-component'
|
||||||
import { createSimpleRemoteIslandProvider } from '../fixtures/remote-provider'
|
import { createSimpleRemoteIslandProvider } from '../fixtures/remote-provider'
|
||||||
@ -133,6 +133,19 @@ describe('runtime server component', () => {
|
|||||||
expect(wrapper.emitted('error')).toHaveLength(1)
|
expect(wrapper.emitted('error')).toHaveLength(1)
|
||||||
vi.mocked(fetch).mockReset()
|
vi.mocked(fetch).mockReset()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('expect NuxtIsland to have parent scopeId', async () => {
|
||||||
|
const wrapper = await mountSuspended(defineComponent({
|
||||||
|
render () {
|
||||||
|
pushScopeId('data-v-654e2b21')
|
||||||
|
const vnode = h(createServerComponent('dummyName'))
|
||||||
|
popScopeId()
|
||||||
|
return vnode
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
expect(wrapper.find('*').attributes()).toHaveProperty('data-v-654e2b21')
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('client components', () => {
|
describe('client components', () => {
|
||||||
@ -186,7 +199,7 @@ describe('client components', () => {
|
|||||||
expect(fetch).toHaveBeenCalledOnce()
|
expect(fetch).toHaveBeenCalledOnce()
|
||||||
|
|
||||||
expect(wrapper.html()).toMatchInlineSnapshot(`
|
expect(wrapper.html()).toMatchInlineSnapshot(`
|
||||||
"<div data-island-uid="4">hello<div data-island-uid="4" data-island-component="Client-12345">
|
"<div data-island-uid="5">hello<div data-island-uid="5" data-island-component="Client-12345">
|
||||||
<div>client component</div>
|
<div>client component</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -212,7 +225,7 @@ describe('client components', () => {
|
|||||||
await wrapper.vm.$.exposed!.refresh()
|
await wrapper.vm.$.exposed!.refresh()
|
||||||
await nextTick()
|
await nextTick()
|
||||||
expect(wrapper.html()).toMatchInlineSnapshot(`
|
expect(wrapper.html()).toMatchInlineSnapshot(`
|
||||||
"<div data-island-uid="4">hello<div>
|
"<div data-island-uid="5">hello<div>
|
||||||
<div>fallback</div>
|
<div>fallback</div>
|
||||||
</div>
|
</div>
|
||||||
</div>"
|
</div>"
|
||||||
@ -305,7 +318,7 @@ describe('client components', () => {
|
|||||||
})
|
})
|
||||||
expect(fetch).toHaveBeenCalledOnce()
|
expect(fetch).toHaveBeenCalledOnce()
|
||||||
expect(wrapper.html()).toMatchInlineSnapshot(`
|
expect(wrapper.html()).toMatchInlineSnapshot(`
|
||||||
"<div data-island-uid="6">hello<div data-island-uid="6" data-island-component="ClientWithSlot-12345">
|
"<div data-island-uid="7">hello<div data-island-uid="7" data-island-component="ClientWithSlot-12345">
|
||||||
<div class="client-component">
|
<div class="client-component">
|
||||||
<div style="display: contents" data-island-uid="" data-island-slot="default">
|
<div style="display: contents" data-island-uid="" data-island-slot="default">
|
||||||
<div>slot in client component</div>
|
<div>slot in client component</div>
|
||||||
|
Loading…
Reference in New Issue
Block a user