mirror of https://github.com/vuejs/core.git
wip: vdom hydration interop
This commit is contained in:
parent
4253b0ce3e
commit
d281d62312
|
@ -9,6 +9,7 @@ import {
|
||||||
FOR_ANCHOR_LABEL,
|
FOR_ANCHOR_LABEL,
|
||||||
IF_ANCHOR_LABEL,
|
IF_ANCHOR_LABEL,
|
||||||
SLOT_ANCHOR_LABEL,
|
SLOT_ANCHOR_LABEL,
|
||||||
|
isString,
|
||||||
} from '@vue/shared'
|
} from '@vue/shared'
|
||||||
|
|
||||||
const Vue = { ...runtimeDom, ...runtimeVapor }
|
const Vue = { ...runtimeDom, ...runtimeVapor }
|
||||||
|
@ -17,7 +18,7 @@ function compile(
|
||||||
sfc: string,
|
sfc: string,
|
||||||
data: runtimeDom.Ref<any>,
|
data: runtimeDom.Ref<any>,
|
||||||
components: Record<string, any> = {},
|
components: Record<string, any> = {},
|
||||||
ssr = false,
|
{ vapor = true, ssr = false } = {},
|
||||||
) {
|
) {
|
||||||
if (!sfc.includes(`<script`)) {
|
if (!sfc.includes(`<script`)) {
|
||||||
sfc =
|
sfc =
|
||||||
|
@ -31,7 +32,7 @@ function compile(
|
||||||
isProd: true,
|
isProd: true,
|
||||||
inlineTemplate: true,
|
inlineTemplate: true,
|
||||||
genDefaultAs: '__sfc__',
|
genDefaultAs: '__sfc__',
|
||||||
vapor: true,
|
vapor,
|
||||||
templateOptions: {
|
templateOptions: {
|
||||||
ssr,
|
ssr,
|
||||||
},
|
},
|
||||||
|
@ -55,17 +56,27 @@ function compile(
|
||||||
|
|
||||||
async function testHydration(
|
async function testHydration(
|
||||||
code: string,
|
code: string,
|
||||||
components: Record<string, string> = {},
|
components: Record<string, string | { code: string; vapor: boolean }> = {},
|
||||||
data: any = ref('foo'),
|
data: any = ref('foo'),
|
||||||
|
{ interop = false, vapor = true } = {},
|
||||||
) {
|
) {
|
||||||
const ssrComponents: any = {}
|
const ssrComponents: any = {}
|
||||||
const clientComponents: any = {}
|
const clientComponents: any = {}
|
||||||
for (const key in components) {
|
for (const key in components) {
|
||||||
clientComponents[key] = compile(components[key], data, clientComponents)
|
const comp = components[key]
|
||||||
ssrComponents[key] = compile(components[key], data, ssrComponents, true)
|
const code = isString(comp) ? comp : comp.code
|
||||||
|
const isVaporComp = !isString(comp) ? comp.vapor : true
|
||||||
|
clientComponents[key] = compile(code, data, clientComponents, {
|
||||||
|
vapor: isVaporComp,
|
||||||
|
ssr: false,
|
||||||
|
})
|
||||||
|
ssrComponents[key] = compile(code, data, ssrComponents, {
|
||||||
|
vapor: isVaporComp,
|
||||||
|
ssr: true,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
const serverComp = compile(code, data, ssrComponents, true)
|
const serverComp = compile(code, data, ssrComponents, { vapor, ssr: true })
|
||||||
const html = await VueServerRenderer.renderToString(
|
const html = await VueServerRenderer.renderToString(
|
||||||
runtimeDom.createSSRApp(serverComp),
|
runtimeDom.createSSRApp(serverComp),
|
||||||
)
|
)
|
||||||
|
@ -73,8 +84,17 @@ async function testHydration(
|
||||||
document.body.appendChild(container)
|
document.body.appendChild(container)
|
||||||
container.innerHTML = html
|
container.innerHTML = html
|
||||||
|
|
||||||
const clientComp = compile(code, data, clientComponents)
|
const clientComp = compile(code, data, clientComponents, {
|
||||||
const app = createVaporSSRApp(clientComp)
|
vapor,
|
||||||
|
ssr: false,
|
||||||
|
})
|
||||||
|
let app
|
||||||
|
if (interop) {
|
||||||
|
app = runtimeDom.createSSRApp(clientComp)
|
||||||
|
app.use(runtimeVapor.vaporInteropPlugin)
|
||||||
|
} else {
|
||||||
|
app = createVaporSSRApp(clientComp)
|
||||||
|
}
|
||||||
app.mount(container)
|
app.mount(container)
|
||||||
return { data, container }
|
return { data, container }
|
||||||
}
|
}
|
||||||
|
@ -84,13 +104,13 @@ const triggerEvent = (type: string, el: Element) => {
|
||||||
el.dispatchEvent(event)
|
el.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('Vapor Mode hydration', () => {
|
delegateEvents('click')
|
||||||
delegateEvents('click')
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
document.body.innerHTML = ''
|
document.body.innerHTML = ''
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('Vapor Mode hydration', () => {
|
||||||
describe('text', () => {
|
describe('text', () => {
|
||||||
test('root text', async () => {
|
test('root text', async () => {
|
||||||
const { data, container } = await testHydration(`
|
const { data, container } = await testHydration(`
|
||||||
|
@ -3816,3 +3836,93 @@ describe('Vapor Mode hydration', () => {
|
||||||
test.todo('Teleport')
|
test.todo('Teleport')
|
||||||
test.todo('Suspense')
|
test.todo('Suspense')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
describe('VDOM hydration interop', () => {
|
||||||
|
test('basic component', async () => {
|
||||||
|
const data = ref(true)
|
||||||
|
const { container } = await testHydration(
|
||||||
|
`<script setup>const data = _data; const components = _components;</script>
|
||||||
|
<template>
|
||||||
|
<components.VaporChild/>
|
||||||
|
</template>`,
|
||||||
|
{
|
||||||
|
VaporChild: {
|
||||||
|
code: `<template>{{ data }}</template>`,
|
||||||
|
vapor: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
{ interop: true, vapor: false },
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.innerHTML).toMatchInlineSnapshot(`"true"`)
|
||||||
|
|
||||||
|
data.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toMatchInlineSnapshot(`"false"`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('nested components (VDOM -> Vapor -> VDOM)', async () => {
|
||||||
|
const data = ref(true)
|
||||||
|
const { container } = await testHydration(
|
||||||
|
`<script setup>const data = _data; const components = _components;</script>
|
||||||
|
<template>
|
||||||
|
<components.VaporChild/>
|
||||||
|
</template>`,
|
||||||
|
{
|
||||||
|
VaporChild: {
|
||||||
|
code: `<template><components.VdomChild/></template>`,
|
||||||
|
vapor: true,
|
||||||
|
},
|
||||||
|
VdomChild: {
|
||||||
|
code: `<script setup>const data = _data;</script>
|
||||||
|
<template>{{ data }}</template>`,
|
||||||
|
vapor: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
{ interop: true, vapor: false },
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.innerHTML).toMatchInlineSnapshot(`"true"`)
|
||||||
|
|
||||||
|
data.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toMatchInlineSnapshot(`"false"`)
|
||||||
|
})
|
||||||
|
|
||||||
|
test.todo('slots', async () => {
|
||||||
|
const data = ref(true)
|
||||||
|
const { container } = await testHydration(
|
||||||
|
`<script setup>const data = _data; const components = _components;</script>
|
||||||
|
<template>
|
||||||
|
<components.VaporChild>
|
||||||
|
<components.VdomChild/>
|
||||||
|
</components.VaporChild>
|
||||||
|
</template>`,
|
||||||
|
{
|
||||||
|
VaporChild: {
|
||||||
|
code: `<template><div><slot/></div></template>`,
|
||||||
|
vapor: true,
|
||||||
|
},
|
||||||
|
VdomChild: {
|
||||||
|
code: `<script setup>const data = _data;</script>
|
||||||
|
<template>{{ data }}</template>`,
|
||||||
|
vapor: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
data,
|
||||||
|
{ interop: true, vapor: false },
|
||||||
|
)
|
||||||
|
|
||||||
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
||||||
|
`"<div><!--[-->true<!--]--><!--slot--></div>"`,
|
||||||
|
)
|
||||||
|
|
||||||
|
data.value = false
|
||||||
|
await nextTick()
|
||||||
|
expect(container.innerHTML).toMatchInlineSnapshot(
|
||||||
|
`"<div><!--[-->false<!--]--><!--slot--></div>"`,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
Loading…
Reference in New Issue