Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(runtime): CSSVars can work with Teleport #7344

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
b2d72c7
fix(runtime): cssVars can work with Teleport
baiwusanyu-c Dec 14, 2022
704be6f
fix(runtime): update code for unit test
baiwusanyu-c Dec 14, 2022
b8e882d
fix(runtime-core): add unit test
baiwusanyu-c Dec 14, 2022
673940c
fix(runtime-core): update code
baiwusanyu-c Dec 16, 2022
b34e64f
fix(runtime-core): update code
baiwusanyu-c Dec 16, 2022
f4a605c
fix(compiler-core): Add teleportIds in vnode to achieve correct rende…
baiwusanyu-c Dec 16, 2022
8020386
fix(runtime-core): Update judgment condition code
baiwusanyu-c Dec 17, 2022
adc9c58
fix(compiler-core): update unit test and support suspense
baiwusanyu-c Dec 17, 2022
80791fc
fix(compiler-core): added suspense's unit test
baiwusanyu-c Dec 17, 2022
ad95ea6
Merge branch 'vuejs:main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Dec 26, 2022
1752fba
Merge branch 'vuejs:main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Jan 2, 2023
fe147fc
Merge branch 'vuejs:main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Jan 9, 2023
0dbec82
Merge branch 'vuejs:main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Jan 14, 2023
be83253
Merge remote-tracking branch 'origin/main' into bwsy/fix/stringify
baiwusanyu-c Feb 4, 2023
3f2107e
Merge remote-tracking branch 'origin/main' into bwsy/fix/stringify
baiwusanyu-c Feb 4, 2023
0fa8a0a
Merge branch 'vuejs:main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Feb 6, 2023
174aa23
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Feb 14, 2023
a6bed2e
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Feb 21, 2023
be7ef16
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Feb 22, 2023
13c9ab6
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Mar 17, 2023
0b7a33f
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Mar 20, 2023
df43c1e
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Mar 23, 2023
10d4368
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Mar 27, 2023
9bc3b32
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 6, 2023
da36b5c
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 10, 2023
5537755
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 12, 2023
50dbdcb
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 14, 2023
7fbc022
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 17, 2023
21c10f8
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 19, 2023
90361f8
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 20, 2023
2dd703d
Merge remote-tracking branch 'upstream/main' into bwsy/fix/teleportCS…
baiwusanyu-c Apr 21, 2023
b7cadc2
Merge branch 'vuejs:main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 25, 2023
fa64b07
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c May 4, 2023
1fc7b21
Merge remote-tracking branch 'origin/main' into bwsy/fix/teleportCSSVars
baiwusanyu-c May 9, 2023
d081bb4
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c May 16, 2023
dbec711
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Jun 6, 2023
69b2dcd
updated code
baiwusanyu-c Jul 12, 2023
6e0af13
Merge remote-tracking branch 'upstream/main' into bwsy/fix/teleportCS…
baiwusanyu-c Oct 20, 2023
97aae5f
Merge remote-tracking branch 'origin/main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Nov 13, 2023
e3e85d5
Merge remote-tracking branch 'origin/main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Dec 19, 2023
a12da2d
Merge remote-tracking branch 'origin/main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Jan 3, 2024
69a4c5f
[autofix.ci] apply automated fixes
autofix-ci[bot] Jan 3, 2024
7067594
chore: updated dts
baiwusanyu-c Jan 3, 2024
5e887ab
Merge remote-tracking branch 'upstream/main' into bwsy/fix/teleportCS…
baiwusanyu-c Mar 27, 2024
4ff76d4
Merge branch 'main' into bwsy/fix/teleportCSSVars
baiwusanyu-c Apr 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
55 changes: 53 additions & 2 deletions packages/runtime-core/__tests__/components/Suspense.spec.ts
Expand Up @@ -8,24 +8,34 @@ import {
KeepAlive,
Suspense,
type SuspenseProps,
Teleport,
h,
nextTick,
nodeOps,
onErrorCaptured,
onMounted,
onUnmounted,
reactive,
ref,
render,
resolveDynamicComponent,
serializeInner,
shallowRef,
watch,
watchEffect,
withCtx,
} from '@vue/runtime-test'
import { computed, createApp, defineComponent, inject, provide } from 'vue'
import {
computed,
createApp,
defineComponent,
inject,
provide,
useCssVars,
} from 'vue'
import type { RawSlots } from 'packages/runtime-core/src/componentSlots'
import { resetSuspenseId } from '../../src/components/Suspense'

import { render as runtimeRender } from '@vue/runtime-dom'
describe('Suspense', () => {
const deps: Promise<any>[] = []

Expand Down Expand Up @@ -2075,6 +2085,47 @@ describe('Suspense', () => {
await Promise.all(deps)
})

test('suspense can render CssVars correctly in teleport', async () => {
document.body.innerHTML = ''
const state = reactive({ color: 'red' })
const root = document.createElement('div')
const target = document.body
const Async = defineAsyncComponent({
render() {
return h('div', 'async')
},
})

const Comp = {
setup() {
useCssVars(() => state)
return () =>
h(Teleport, { to: target }, [
h(Suspense, null, {
default: withCtx(() => h(Async)),
fallback: withCtx(() => h('div', 'fallback')),
}),
])
},
}

runtimeRender(h(Comp), root)
await nextTick()
expect(target.children.length).toBe(1)
for (const c of [].slice.call(target.children as any)) {
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
}
expect(target.children[0].innerHTML).toBe('fallback')

await Promise.all(deps)
await nextTick()
expect(target.children.length).toBe(1)
for (const c of [].slice.call(target.children as any)) {
expect((c as HTMLElement).style.getPropertyValue(`--color`)).toBe('red')
}
expect(target.children[0].innerHTML).toBe('async')
})

describe('warnings', () => {
// base function to check if a combination of slots warns or not
function baseCheckWarn(
Expand Down
96 changes: 92 additions & 4 deletions packages/runtime-core/src/components/Teleport.ts
Expand Up @@ -7,10 +7,16 @@ import {
type RendererInternals,
type RendererNode,
type RendererOptions,
queuePostRenderEffect,
traverseStaticChildren,
} from '../renderer'
import type { VNode, VNodeArrayChildren, VNodeProps } from '../vnode'
import { ShapeFlags, isString } from '@vue/shared'
import type {
VNode,
VNodeArrayChildren,
VNodeNormalizedChildren,
VNodeProps,
} from '../vnode'
import { ShapeFlags, isArray, isString } from '@vue/shared'
import { warn } from '../warning'
import { isHmrUpdating } from '../hmr'

Expand All @@ -20,9 +26,69 @@ export interface TeleportProps {
to: string | RendererElement | null | undefined
disabled?: boolean
}
export const teleportUTMap: Record<
number,
((vars?: Record<string, string>) => void) | null
> = {}

export const isTeleport = (type: any): boolean => type.__isTeleport

/**
* @private
*/
export const setTeleportOwnerAttrToEl = (
props: (VNodeProps & { [key: string]: any }) | null,
vnode: VNode,
) => {
const teleportIds = vnode.teleportIds
if (teleportIds !== null && teleportIds !== undefined) {
if (!props) {
props = {}
}
props['data-v-owner'] = teleportIds[teleportIds.length - 1]
}
return props
}
/**
* In the fast path, sometimes element updates will not re-update `teleport`
* E.g
* <teleport to="body">
* <Comp>
* <div class="text" v-if="showThing">
* test
* </div>
* </Comp>
* </teleport>
* TODO: comment
* @private
*/
export const updateTeleportsCssVarsFast = (
vnode: VNode,
parentSuspense: SuspenseBoundary | null,
) => {
queuePostRenderEffect(() => {
const teleportIds = vnode.teleportIds
if (teleportIds !== null && teleportIds !== undefined) {
teleportIds.forEach((id: number) => {
if (teleportUTMap[id]) {
teleportUTMap[id]!()
}
})
}
}, parentSuspense)
}
export const setTeleportIdTOVNode = (
vnode: VNode,
parentComponent: ComponentInternalInstance | null,
) => {
if (parentComponent) {
if (
parentComponent.vnode.teleportIds !== null &&
parentComponent.vnode.teleportIds !== undefined
) {
vnode.teleportIds = parentComponent.vnode.teleportIds
}
}
}
const isTeleportDisabled = (props: VNode['props']): boolean =>
props && (props.disabled || props.disabled === '')

Expand Down Expand Up @@ -110,6 +176,9 @@ export const TeleportImpl = {
insert(mainAnchor, container, anchor)
const target = (n2.target = resolveTarget(n2.props, querySelector))
const targetAnchor = (n2.targetAnchor = createText(''))

initTeleportIds(children, n2)

if (target) {
insert(targetAnchor, target)
// #2652 we could be teleporting from a non-SVG tree into an SVG tree
Expand Down Expand Up @@ -393,7 +462,6 @@ function hydrateTeleport(
break
}
}

hydrateChildren(
targetNode,
vnode,
Expand Down Expand Up @@ -434,3 +502,23 @@ function updateCssVars(vnode: VNode) {
ctx.ut()
}
}

function initTeleportIds(children: VNodeNormalizedChildren, vnode: VNode) {
if (!children) return
const ctx = vnode.ctx
if (children && isArray(children)) {
;(children as VNode[]).forEach((c: VNode | null) => {
if (c && c.__v_isVNode && ctx && ctx.ut && (ctx.uid || ctx.uid === 0)) {
if (!c.teleportIds) c.teleportIds = []
c.teleportIds.push(ctx.uid)

if (c.ssContent && !c.ssContent.teleportIds) {
if (!c.ssContent.teleportIds) {
c.ssContent.teleportIds = []
}
c.ssContent.teleportIds.push(ctx.uid)
}
}
})
}
}
6 changes: 5 additions & 1 deletion packages/runtime-core/src/index.ts
Expand Up @@ -101,7 +101,11 @@ export { createVNode, cloneVNode, mergeProps, isVNode } from './vnode'
// VNode types
export { Fragment, Text, Comment, Static, type VNodeRef } from './vnode'
// Built-in components
export { Teleport, type TeleportProps } from './components/Teleport'
export {
Teleport,
type TeleportProps,
teleportUTMap,
} from './components/Teleport'
export { Suspense, type SuspenseProps } from './components/Suspense'
export { KeepAlive, type KeepAliveProps } from './components/KeepAlive'
export {
Expand Down
19 changes: 16 additions & 3 deletions packages/runtime-core/src/renderer.ts
Expand Up @@ -57,6 +57,11 @@ import {
queueEffectWithSuspense,
} from './components/Suspense'
import type { TeleportImpl, TeleportVNode } from './components/Teleport'
import {
setTeleportIdTOVNode,
setTeleportOwnerAttrToEl,
updateTeleportsCssVarsFast,
} from './components/Teleport'
import { type KeepAliveContext, isKeepAlive } from './components/KeepAlive'
import { isHmrUpdating, registerHMR, unregisterHMR } from './hmr'
import { type RootHydrateFunction, createHydrationFunctions } from './hydration'
Expand Down Expand Up @@ -592,7 +597,7 @@ function baseCreateRenderer(
} else if (n2.type === 'math') {
namespace = 'mathml'
}

setTeleportIdTOVNode(n2, parentComponent)
if (n1 == null) {
mountElement(
n2,
Expand Down Expand Up @@ -629,8 +634,8 @@ function baseCreateRenderer(
) => {
let el: RendererElement
let vnodeHook: VNodeHook | undefined | null
const { props, shapeFlag, transition, dirs } = vnode

const { shapeFlag, transition, dirs } = vnode
let props = setTeleportOwnerAttrToEl(vnode.props, vnode)
el = vnode.el = hostCreateElement(
vnode.type as string,
namespace,
Expand Down Expand Up @@ -714,6 +719,9 @@ function baseCreateRenderer(
transition!.beforeEnter(el)
}
hostInsert(el, container, anchor)

updateTeleportsCssVarsFast(vnode, parentSuspense)

if (
(vnodeHook = props && props.onVnodeMounted) ||
needCallTransitionHooks ||
Expand Down Expand Up @@ -1079,6 +1087,8 @@ function baseCreateRenderer(
: fragmentSlotScopeIds
}

setTeleportIdTOVNode(n2, parentComponent)

if (n1 == null) {
hostInsert(fragmentStartAnchor, container, anchor)
hostInsert(fragmentEndAnchor, container, anchor)
Expand Down Expand Up @@ -1164,6 +1174,9 @@ function baseCreateRenderer(
optimized: boolean,
) => {
n2.slotScopeIds = slotScopeIds

setTeleportIdTOVNode(n2, parentComponent)

if (n1 == null) {
if (n2.shapeFlag & ShapeFlags.COMPONENT_KEPT_ALIVE) {
;(parentComponent!.ctx as KeepAliveContext).activate(
Expand Down
1 change: 1 addition & 0 deletions packages/runtime-core/src/vnode.ts
Expand Up @@ -233,6 +233,7 @@ export interface VNode<
* @internal custom element interception hook
*/
ce?: (instance: ComponentInternalInstance) => void
teleportIds?: number[]
}

// Since v-if and v-for are the two possible ways node structure can dynamically
Expand Down