diff --git a/packages/runtime-core/__tests__/componentPublicInstance.spec.ts b/packages/runtime-core/__tests__/componentPublicInstance.spec.ts index 37c228a5104..346d1d4e4d5 100644 --- a/packages/runtime-core/__tests__/componentPublicInstance.spec.ts +++ b/packages/runtime-core/__tests__/componentPublicInstance.spec.ts @@ -167,13 +167,26 @@ describe('component: proxy', () => { data() { return { foo: 0, + $foo: 0, } }, + computed: { + cmp: () => { + throw new Error('value of cmp should not be accessed') + }, + $cmp: () => { + throw new Error('value of $cmp should not be read') + }, + }, setup() { return { bar: 1, } }, + __cssModules: { + $style: {}, + cssStyles: {}, + }, mounted() { instanceProxy = this }, @@ -181,6 +194,7 @@ describe('component: proxy', () => { const app = createApp(Comp, { msg: 'hello' }) app.config.globalProperties.global = 1 + app.config.globalProperties.$global = 1 app.mount(nodeOps.createElement('div')) @@ -188,12 +202,20 @@ describe('component: proxy', () => { expect('msg' in instanceProxy).toBe(true) // data expect('foo' in instanceProxy).toBe(true) - // ctx + expect('$foo' in instanceProxy).toBe(false) + // setupState expect('bar' in instanceProxy).toBe(true) + // ctx + expect('cmp' in instanceProxy).toBe(true) + expect('$cmp' in instanceProxy).toBe(true) // public properties expect('$el' in instanceProxy).toBe(true) + // CSS modules + expect('$style' in instanceProxy).toBe(true) + expect('cssStyles' in instanceProxy).toBe(true) // global properties expect('global' in instanceProxy).toBe(true) + expect('$global' in instanceProxy).toBe(true) // non-existent expect('$foobar' in instanceProxy).toBe(false) @@ -202,11 +224,15 @@ describe('component: proxy', () => { // #4962 triggering getter should not cause non-existent property to // pass the has check instanceProxy.baz + instanceProxy.$baz expect('baz' in instanceProxy).toBe(false) + expect('$baz' in instanceProxy).toBe(false) // set non-existent (goes into proxyTarget sink) instanceProxy.baz = 1 expect('baz' in instanceProxy).toBe(true) + instanceProxy.$baz = 1 + expect('$baz' in instanceProxy).toBe(true) // dev mode ownKeys check for console inspection // should only expose own keys @@ -214,7 +240,10 @@ describe('component: proxy', () => { 'msg', 'bar', 'foo', + 'cmp', + '$cmp', 'baz', + '$baz', ]) }) diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index e9e7770ebd9..58c18764ee1 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -575,19 +575,20 @@ export const PublicInstanceProxyHandlers: ProxyHandler = { has( { - _: { data, setupState, accessCache, ctx, appContext, propsOptions }, + _: { data, setupState, accessCache, ctx, appContext, propsOptions, type }, }: ComponentRenderContext, key: string, ) { - let normalizedProps - return ( - !!accessCache![key] || - (data !== EMPTY_OBJ && hasOwn(data, key)) || + let normalizedProps, cssModules + return !!( + accessCache![key] || + (data !== EMPTY_OBJ && key[0] !== '$' && hasOwn(data, key)) || hasSetupBinding(setupState, key) || ((normalizedProps = propsOptions[0]) && hasOwn(normalizedProps, key)) || hasOwn(ctx, key) || hasOwn(publicPropertiesMap, key) || - hasOwn(appContext.config.globalProperties, key) + hasOwn(appContext.config.globalProperties, key) || + ((cssModules = type.__cssModules) && cssModules[key]) ) },