wip(vapor): templateRef adjustments

This commit is contained in:
Evan You 2024-12-12 22:34:35 +08:00
parent e38805354d
commit 0d1df25f23
No known key found for this signature in database
GPG Key ID: 00E9AB7A6704CE0A
14 changed files with 170 additions and 110 deletions

View File

@ -16,6 +16,7 @@ import {
codeFragmentToString, codeFragmentToString,
genCall, genCall,
} from './generators/utils' } from './generators/utils'
import { setTemplateRefIdent } from './generators/templateRef'
export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'> export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'>
@ -110,19 +111,21 @@ export function generate(
', ', ', ',
) )
if (inline) { if (!inline) {
// push(`((${signature}) => {`)
} else {
push(NEWLINE, `export function ${functionName}(${signature}) {`) push(NEWLINE, `export function ${functionName}(${signature}) {`)
} }
push(INDENT_START) push(INDENT_START)
if (ir.hasTemplateRef) {
push(
NEWLINE,
`const ${setTemplateRefIdent} = ${context.helper('createTemplateRefSetter')}()`,
)
}
push(...genBlockContent(ir.block, context, true)) push(...genBlockContent(ir.block, context, true))
push(INDENT_END, NEWLINE) push(INDENT_END, NEWLINE)
if (inline) { if (!inline) {
// push('})()')
} else {
push('}') push('}')
} }

View File

@ -67,9 +67,14 @@ export function genOperation(
return genDeclareOldRef(oper) return genDeclareOldRef(oper)
case IRNodeTypes.SLOT_OUTLET_NODE: case IRNodeTypes.SLOT_OUTLET_NODE:
return genSlotOutlet(oper, context) return genSlotOutlet(oper, context)
case IRNodeTypes.WITH_DIRECTIVE:
return [] // TODO
default:
const exhaustiveCheck: never = oper
throw new Error(
`Unhandled operation type in genOperation: ${exhaustiveCheck}`,
)
} }
return []
} }
export function genEffects( export function genEffects(

View File

@ -3,16 +3,17 @@ import type { CodegenContext } from '../generate'
import type { DeclareOldRefIRNode, SetTemplateRefIRNode } from '../ir' import type { DeclareOldRefIRNode, SetTemplateRefIRNode } from '../ir'
import { type CodeFragment, NEWLINE, genCall } from './utils' import { type CodeFragment, NEWLINE, genCall } from './utils'
export const setTemplateRefIdent = `_setTemplateRef`
export function genSetTemplateRef( export function genSetTemplateRef(
oper: SetTemplateRefIRNode, oper: SetTemplateRefIRNode,
context: CodegenContext, context: CodegenContext,
): CodeFragment[] { ): CodeFragment[] {
const { helper } = context
return [ return [
NEWLINE, NEWLINE,
oper.effect && `r${oper.element} = `, oper.effect && `r${oper.element} = `,
...genCall( ...genCall(
helper('setRef'), setTemplateRefIdent, // will be generated in root scope
`n${oper.element}`, `n${oper.element}`,
genExpression(oper.value, context), genExpression(oper.value, context),
oper.effect ? `r${oper.element}` : oper.refFor ? 'void 0' : undefined, oper.effect ? `r${oper.element}` : oper.refFor ? 'void 0' : undefined,

View File

@ -63,6 +63,7 @@ export interface RootIRNode {
component: Set<string> component: Set<string>
directive: Set<string> directive: Set<string>
block: BlockIRNode block: BlockIRNode
hasTemplateRef: boolean
} }
export interface IfIRNode extends BaseIRNode { export interface IfIRNode extends BaseIRNode {

View File

@ -220,6 +220,7 @@ export function transform(
component: new Set(), component: new Set(),
directive: new Set(), directive: new Set(),
block: newBlock(node), block: newBlock(node),
hasTemplateRef: false,
} }
const context = new TransformContext(ir, node, options) const context = new TransformContext(ir, node, options)

View File

@ -15,6 +15,8 @@ export const transformTemplateRef: NodeTransform = (node, context) => {
const dir = findProp(node, 'ref', false, true) const dir = findProp(node, 'ref', false, true)
if (!dir) return if (!dir) return
context.ir.hasTemplateRef = true
let value: SimpleExpressionNode let value: SimpleExpressionNode
if (dir.type === NodeTypes.DIRECTIVE) { if (dir.type === NodeTypes.DIRECTIVE) {
value = dir.exp || normalizeBindShorthand(dir.arg!, context) value = dir.exp || normalizeBindShorthand(dir.arg!, context)

View File

@ -1,5 +1,5 @@
import { type ShallowRef, readonly, shallowRef } from '@vue/reactivity' import { type ShallowRef, readonly, shallowRef } from '@vue/reactivity'
import { getCurrentInstance } from '../component' import { getCurrentGenericInstance } from '../component'
import { warn } from '../warning' import { warn } from '../warning'
import { EMPTY_OBJ } from '@vue/shared' import { EMPTY_OBJ } from '@vue/shared'
@ -8,7 +8,7 @@ export const knownTemplateRefs: WeakSet<ShallowRef> = new WeakSet()
export function useTemplateRef<T = unknown, Keys extends string = string>( export function useTemplateRef<T = unknown, Keys extends string = string>(
key: Keys, key: Keys,
): Readonly<ShallowRef<T | null>> { ): Readonly<ShallowRef<T | null>> {
const i = getCurrentInstance() const i = getCurrentGenericInstance()
const r = shallowRef(null) const r = shallowRef(null)
if (i) { if (i) {
const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs const refs = i.refs === EMPTY_OBJ ? (i.refs = {}) : i.refs

View File

@ -7,7 +7,8 @@ import {
} from '../directives/vShow' } from '../directives/vShow'
import { CSS_VAR_TEXT } from '../helpers/useCssVars' import { CSS_VAR_TEXT } from '../helpers/useCssVars'
type Style = string | Record<string, string | string[]> | null | undefined type Style = StyleValue | Record<string, StyleValue | StyleValue[]>
type StyleValue = string | null | undefined
const displayRE = /(^|;)\s*display\s*:/ const displayRE = /(^|;)\s*display\s*:/
@ -70,7 +71,7 @@ const importantRE = /\s*!important$/
function setStyle( function setStyle(
style: CSSStyleDeclaration, style: CSSStyleDeclaration,
name: string, name: string,
val: string | string[], val: StyleValue | StyleValue[],
) { ) {
if (isArray(val)) { if (isArray(val)) {
val.forEach(v => setStyle(style, name, v)) val.forEach(v => setStyle(style, name, v))

View File

@ -1,6 +1,6 @@
import { ref, shallowRef } from '@vue/reactivity' import { ref, shallowRef } from '@vue/reactivity'
import { type VaporComponentInstance, createComponent } from '../src/component' import { type VaporComponentInstance, createComponent } from '../src/component'
import { setRef } from '../src/dom/templateRef' import { setRef } from '../src/apiTemplateRef'
import { makeRender } from './_utils' import { makeRender } from './_utils'
import { currentInstance } from '@vue/runtime-dom' import { currentInstance } from '@vue/runtime-dom'
import { defineVaporComponent } from '../src/apiDefineComponent' import { defineVaporComponent } from '../src/apiDefineComponent'
@ -8,7 +8,8 @@ import { defineVaporComponent } from '../src/apiDefineComponent'
const define = makeRender() const define = makeRender()
describe('api: expose', () => { describe('api: expose', () => {
test.todo('via setup context + template ref', () => { test('via setup context + template ref', () => {
let i: any
const Child = defineVaporComponent({ const Child = defineVaporComponent({
setup(_, { expose }) { setup(_, { expose }) {
expose({ expose({
@ -20,19 +21,20 @@ describe('api: expose', () => {
}) })
const childRef = ref() const childRef = ref()
define({ define({
render: () => { setup: () => {
const n0 = createComponent(Child) const n0 = (i = createComponent(Child))
setRef(currentInstance as VaporComponentInstance, n0, childRef)
return n0 return n0
}, },
}).render() }).render()
expect(childRef.value).toBeTruthy() expect(childRef.value).toBe(i.exposeProxy)
expect(childRef.value.foo).toBe(1) expect(childRef.value.foo).toBe(1)
expect(childRef.value.bar).toBe(2) expect(childRef.value.bar).toBe(2)
expect(childRef.value.baz).toBeUndefined() expect(childRef.value.baz).toBeUndefined()
}) })
test.todo('via setup context + template ref (expose empty)', () => { test('via setup context + template ref (expose empty)', () => {
let childInstance: VaporComponentInstance | null = null let childInstance: VaporComponentInstance | null = null
const Child = defineVaporComponent({ const Child = defineVaporComponent({
setup(_) { setup(_) {
@ -42,14 +44,14 @@ describe('api: expose', () => {
}) })
const childRef = shallowRef() const childRef = shallowRef()
define({ define({
render: () => { setup: () => {
const n0 = createComponent(Child) const n0 = createComponent(Child)
setRef(n0, childRef) setRef(currentInstance as VaporComponentInstance, n0, childRef)
return n0 return n0
}, },
}).render() }).render()
expect(childInstance!.exposed).toBeUndefined() expect(childInstance!.exposed).toBeNull()
expect(childRef.value).toBe(childInstance!) expect(childRef.value).toBe(childInstance!)
}) })

View File

@ -1,10 +1,10 @@
import type { NodeRef } from '../../src/dom/templateRef' import type { NodeRef } from '../../src/apiTemplateRef'
import { import {
createFor, createFor,
createIf, createIf,
createTemplateRefSetter,
insert, insert,
renderEffect, renderEffect,
setRef,
setText, setText,
template, template,
} from '../../src' } from '../../src'
@ -19,7 +19,7 @@ import {
const define = makeRender() const define = makeRender()
describe.todo('api: template ref', () => { describe('api: template ref', () => {
test('string ref mount', () => { test('string ref mount', () => {
const t0 = template('<div ref="refKey"></div>') const t0 = template('<div ref="refKey"></div>')
const el = ref(null) const el = ref(null)
@ -31,7 +31,7 @@ describe.todo('api: template ref', () => {
}, },
render() { render() {
const n0 = t0() const n0 = t0()
setRef(n0 as Element, 'refKey') createTemplateRefSetter()(n0 as Element, 'refKey')
return n0 return n0
}, },
}) })
@ -57,7 +57,7 @@ describe.todo('api: template ref', () => {
const n0 = t0() const n0 = t0()
let r0: NodeRef | undefined let r0: NodeRef | undefined
renderEffect(() => { renderEffect(() => {
r0 = setRef(n0 as Element, refKey.value, r0) r0 = createTemplateRefSetter()(n0 as Element, refKey.value, r0)
}) })
return n0 return n0
}, },
@ -72,7 +72,7 @@ describe.todo('api: template ref', () => {
expect(fooEl.value).toBe(null) expect(fooEl.value).toBe(null)
}) })
it('string ref unmount', async () => { it.todo('string ref unmount', async () => {
const t0 = template('<div></div>') const t0 = template('<div></div>')
const el = ref(null) const el = ref(null)
const toggle = ref(true) const toggle = ref(true)
@ -84,6 +84,7 @@ describe.todo('api: template ref', () => {
} }
}, },
render() { render() {
const setRef = createTemplateRefSetter()
const n0 = createIf( const n0 = createIf(
() => toggle.value, () => toggle.value,
() => { () => {
@ -109,7 +110,7 @@ describe.todo('api: template ref', () => {
const { render } = define({ const { render } = define({
render() { render() {
const n0 = t0() const n0 = t0()
setRef(n0 as Element, fn) createTemplateRefSetter()(n0 as Element, fn)
return n0 return n0
}, },
}) })
@ -129,7 +130,7 @@ describe.todo('api: template ref', () => {
const n0 = t0() const n0 = t0()
let r0: NodeRef | undefined let r0: NodeRef | undefined
renderEffect(() => { renderEffect(() => {
r0 = setRef(n0 as Element, fn.value, r0) r0 = createTemplateRefSetter()(n0 as Element, fn.value, r0)
}) })
return n0 return n0
}, },
@ -148,7 +149,7 @@ describe.todo('api: template ref', () => {
expect(fn2.mock.calls[0][0]).toBe(host.children[0]) expect(fn2.mock.calls[0][0]).toBe(host.children[0])
}) })
it('function ref unmount', async () => { it.todo('function ref unmount', async () => {
const fn = vi.fn() const fn = vi.fn()
const toggle = ref(true) const toggle = ref(true)
@ -159,7 +160,7 @@ describe.todo('api: template ref', () => {
() => toggle.value, () => toggle.value,
() => { () => {
const n1 = t0() const n1 = t0()
setRef(n1 as Element, fn) createTemplateRefSetter()(n1 as Element, fn)
return n1 return n1
}, },
) )
@ -185,7 +186,7 @@ describe.todo('api: template ref', () => {
}, },
render() { render() {
const n0 = t0() const n0 = t0()
setRef(n0 as Element, 'refKey') createTemplateRefSetter()(n0 as Element, 'refKey')
return n0 return n0
}, },
}) })
@ -213,9 +214,9 @@ describe.todo('api: template ref', () => {
const n0 = t0() const n0 = t0()
const n1 = t1() const n1 = t1()
const n2 = t2() const n2 = t2()
setRef(n0 as Element, 'refKey1') createTemplateRefSetter()(n0 as Element, 'refKey1')
setRef(n1 as Element, 'refKey2') createTemplateRefSetter()(n1 as Element, 'refKey2')
setRef(n2 as Element, 'refKey3') createTemplateRefSetter()(n2 as Element, 'refKey3')
return [n0, n1, n2] return [n0, n1, n2]
}, },
}) })
@ -234,7 +235,7 @@ describe.todo('api: template ref', () => {
const { render } = define({ const { render } = define({
render() { render() {
const n0 = t0() const n0 = t0()
setRef(n0 as Element, el) createTemplateRefSetter()(n0 as Element, el)
renderEffect(() => { renderEffect(() => {
setText(n0, el.value && el.value.getAttribute('id')) setText(n0, el.value && el.value.getAttribute('id'))
}) })
@ -265,10 +266,18 @@ describe.todo('api: template ref', () => {
let r0: NodeRef | undefined let r0: NodeRef | undefined
let r1: NodeRef | undefined let r1: NodeRef | undefined
renderEffect(() => { renderEffect(() => {
r0 = setRef(n0 as Element, refToggle.value ? 'foo' : 'bar', r0) r0 = createTemplateRefSetter()(
n0 as Element,
refToggle.value ? 'foo' : 'bar',
r0,
)
}) })
renderEffect(() => { renderEffect(() => {
r1 = setRef(n1 as Element, refToggle.value ? 'bar' : 'foo', r1) r1 = createTemplateRefSetter()(
n1 as Element,
refToggle.value ? 'bar' : 'foo',
r1,
)
}) })
watchEffect( watchEffect(
() => { () => {
@ -297,7 +306,7 @@ describe.todo('api: template ref', () => {
}) })
// #1789 // #1789
test('toggle the same ref to different elements', async () => { test.todo('toggle the same ref to different elements', async () => {
const refToggle = ref(false) const refToggle = ref(false)
const spy = vi.fn() const spy = vi.fn()
@ -306,6 +315,7 @@ describe.todo('api: template ref', () => {
const { render } = define({ const { render } = define({
render() { render() {
const instance = currentInstance! const instance = currentInstance!
const setRef = createTemplateRefSetter()
const n0 = createIf( const n0 = createIf(
() => refToggle.value, () => refToggle.value,
() => { () => {
@ -341,7 +351,7 @@ describe.todo('api: template ref', () => {
}) })
// compiled output of v-for + template ref // compiled output of v-for + template ref
test('ref in v-for', async () => { test.todo('ref in v-for', async () => {
const show = ref(true) const show = ref(true)
const list = reactive([1, 2, 3]) const list = reactive([1, 2, 3])
const listRefs = ref([]) const listRefs = ref([])
@ -359,7 +369,12 @@ describe.todo('api: template ref', () => {
() => list, () => list,
state => { state => {
const n1 = t1() const n1 = t1()
setRef(n1 as Element, listRefs, undefined, true) createTemplateRefSetter()(
n1 as Element,
listRefs,
undefined,
true,
)
renderEffect(() => { renderEffect(() => {
const [item] = state const [item] = state
setText(n1, item) setText(n1, item)
@ -396,7 +411,7 @@ describe.todo('api: template ref', () => {
expect(mapRefs()).toMatchObject(['2', '3', '4']) expect(mapRefs()).toMatchObject(['2', '3', '4'])
}) })
test('named ref in v-for', async () => { test.todo('named ref in v-for', async () => {
const show = ref(true) const show = ref(true)
const list = reactive([1, 2, 3]) const list = reactive([1, 2, 3])
const listRefs = ref([]) const listRefs = ref([])
@ -417,7 +432,12 @@ describe.todo('api: template ref', () => {
() => list, () => list,
state => { state => {
const n1 = t1() const n1 = t1()
setRef(n1 as Element, 'listRefs', undefined, true) createTemplateRefSetter()(
n1 as Element,
'listRefs',
undefined,
true,
)
renderEffect(() => { renderEffect(() => {
const [item] = state const [item] = state
setText(n1, item) setText(n1, item)
@ -455,7 +475,9 @@ describe.todo('api: template ref', () => {
}) })
// #6697 v-for ref behaves differently under production and development // #6697 v-for ref behaves differently under production and development
test('named ref in v-for , should be responsive when rendering', async () => { test.todo(
'named ref in v-for , should be responsive when rendering',
async () => {
const list = ref([1, 2, 3]) const list = ref([1, 2, 3])
const listRefs = ref([]) const listRefs = ref([])
@ -473,7 +495,12 @@ describe.todo('api: template ref', () => {
() => list.value, () => list.value,
state => { state => {
const n4 = t1() const n4 = t1()
setRef(n4 as Element, 'listRefs', undefined, true) createTemplateRefSetter()(
n4 as Element,
'listRefs',
undefined,
true,
)
renderEffect(() => { renderEffect(() => {
const [item] = state const [item] = state
setText(n4, item) setText(n4, item)
@ -507,7 +534,8 @@ describe.todo('api: template ref', () => {
expect(host.innerHTML).toBe( expect(host.innerHTML).toBe(
'<div><div>[object HTMLLIElement],[object HTMLLIElement]</div><ul><li>2</li><li>3</li><!--for--></ul></div>', '<div><div>[object HTMLLIElement],[object HTMLLIElement]</div><ul><li>2</li><li>3</li><!--for--></ul></div>',
) )
}) },
)
// TODO: need to implement Component slots // TODO: need to implement Component slots
// test('string ref inside slots', async () => { // test('string ref inside slots', async () => {
@ -523,7 +551,7 @@ describe.todo('api: template ref', () => {
// spy(this.$refs.foo.tag) // spy(this.$refs.foo.tag)
// }) // })
// const n0 = createComponent(Child) // const n0 = createComponent(Child)
// setRef(n0, 'foo') // createTemplateRefSetter()(n0, 'foo')
// return n0 // return n0
// }, // },
// }) // })

View File

@ -9,7 +9,7 @@ import {
import { createComponent, setRef, template } from '../src' import { createComponent, setRef, template } from '../src'
import { makeRender } from './_utils' import { makeRender } from './_utils'
import type { VaporComponent } from '../src/component' import type { VaporComponent } from '../src/component'
import type { RefEl } from '../src/dom/templateRef' import type { RefEl } from '../src/apiTemplateRef'
const define = makeRender() const define = makeRender()

View File

@ -4,7 +4,7 @@ import {
currentInstance, currentInstance,
getExposed, getExposed,
isVaporComponent, isVaporComponent,
} from '../component' } from './component'
import { import {
type SchedulerJob, type SchedulerJob,
callWithErrorHandling, callWithErrorHandling,
@ -23,30 +23,41 @@ import {
export type NodeRef = string | Ref | ((ref: Element) => void) export type NodeRef = string | Ref | ((ref: Element) => void)
export type RefEl = Element | VaporComponentInstance export type RefEl = Element | VaporComponentInstance
export type setRefFn = (
el: RefEl,
ref: NodeRef,
oldRef?: NodeRef,
refFor?: boolean,
) => NodeRef | undefined
export function createTemplateRefSetter(): setRefFn {
const instance = currentInstance as VaporComponentInstance
return (...args) => setRef(instance, ...args)
}
/** /**
* Function for handling a template ref * Function for handling a template ref
*/ */
export function setRef( export function setRef(
instance: VaporComponentInstance,
el: RefEl, el: RefEl,
ref: NodeRef, ref: NodeRef,
oldRef?: NodeRef, oldRef?: NodeRef,
refFor = false, refFor = false,
): NodeRef | undefined { ): NodeRef | undefined {
if (!currentInstance || currentInstance.isUnmounted) return if (!instance || instance.isUnmounted) return
const setupState = currentInstance.setupState || {} const setupState: any = __DEV__ ? instance.setupState || {} : null
const refValue = isVaporComponent(el) ? getExposed(el) || el : el const refValue = isVaporComponent(el) ? getExposed(el) || el : el
const refs = const refs =
currentInstance.refs === EMPTY_OBJ instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
? (currentInstance.refs = {})
: currentInstance.refs
// dynamic ref changed. unset old ref // dynamic ref changed. unset old ref
if (oldRef != null && oldRef !== ref) { if (oldRef != null && oldRef !== ref) {
if (isString(oldRef)) { if (isString(oldRef)) {
refs[oldRef] = null refs[oldRef] = null
if (hasOwn(setupState, oldRef)) { if (__DEV__ && hasOwn(setupState, oldRef)) {
setupState[oldRef] = null setupState[oldRef] = null
} }
} else if (isRef(oldRef)) { } else if (isRef(oldRef)) {
@ -66,6 +77,7 @@ export function setRef(
} }
invokeRefSetter(refValue) invokeRefSetter(refValue)
// TODO this gets called repeatedly in renderEffect when it's dynamic ref?
onScopeDispose(() => invokeRefSetter()) onScopeDispose(() => invokeRefSetter())
} else { } else {
const _isString = isString(ref) const _isString = isString(ref)
@ -76,7 +88,7 @@ export function setRef(
const doSet: SchedulerJob = () => { const doSet: SchedulerJob = () => {
if (refFor) { if (refFor) {
existing = _isString existing = _isString
? hasOwn(setupState, ref) ? __DEV__ && hasOwn(setupState, ref)
? setupState[ref] ? setupState[ref]
: refs[ref] : refs[ref]
: ref.value : ref.value
@ -85,7 +97,7 @@ export function setRef(
existing = [refValue] existing = [refValue]
if (_isString) { if (_isString) {
refs[ref] = existing refs[ref] = existing
if (hasOwn(setupState, ref)) { if (__DEV__ && hasOwn(setupState, ref)) {
setupState[ref] = refs[ref] setupState[ref] = refs[ref]
// if setupState[ref] is a reactivity ref, // if setupState[ref] is a reactivity ref,
// the existing will also become reactivity too // the existing will also become reactivity too
@ -100,7 +112,7 @@ export function setRef(
} }
} else if (_isString) { } else if (_isString) {
refs[ref] = refValue refs[ref] = refValue
if (hasOwn(setupState, ref)) { if (__DEV__ && hasOwn(setupState, ref)) {
setupState[ref] = refValue setupState[ref] = refValue
} }
} else if (_isRef) { } else if (_isRef) {
@ -112,13 +124,14 @@ export function setRef(
doSet.id = -1 doSet.id = -1
queuePostFlushCb(doSet) queuePostFlushCb(doSet)
// TODO this gets called repeatedly in renderEffect when it's dynamic ref?
onScopeDispose(() => { onScopeDispose(() => {
queuePostFlushCb(() => { queuePostFlushCb(() => {
if (isArray(existing)) { if (isArray(existing)) {
remove(existing, refValue) remove(existing, refValue)
} else if (_isString) { } else if (_isString) {
refs[ref] = null refs[ref] = null
if (hasOwn(setupState, ref)) { if (__DEV__ && hasOwn(setupState, ref)) {
setupState[ref] = null setupState[ref] = null
} }
} else if (_isRef) { } else if (_isRef) {
@ -127,7 +140,7 @@ export function setRef(
}) })
}) })
} else if (__DEV__) { } else if (__DEV__) {
// warn('Invalid template ref type:', ref, `(${typeof ref})`) warn('Invalid template ref type:', ref, `(${typeof ref})`)
} }
} }
return ref return ref

View File

@ -31,6 +31,7 @@ import {
pauseTracking, pauseTracking,
proxyRefs, proxyRefs,
resetTracking, resetTracking,
unref,
} from '@vue/reactivity' } from '@vue/reactivity'
import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared' import { EMPTY_OBJ, invokeArrayFns, isFunction, isString } from '@vue/shared'
import { import {
@ -485,7 +486,9 @@ export function getExposed(
if (instance.exposed) { if (instance.exposed) {
return ( return (
instance.exposeProxy || instance.exposeProxy ||
(instance.exposeProxy = proxyRefs(markRaw(instance.exposed))) (instance.exposeProxy = new Proxy(markRaw(instance.exposed), {
get: (target, key) => unref(target[key as any]),
}))
) )
} }
} }

View File

@ -25,4 +25,4 @@ export {
export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event' export { on, delegate, delegateEvents, setDynamicEvents } from './dom/event'
export { createIf } from './apiCreateIf' export { createIf } from './apiCreateIf'
export { createFor } from './apiCreateFor' export { createFor } from './apiCreateFor'
export { setRef } from './dom/templateRef' export { createTemplateRefSetter } from './apiTemplateRef'