Skip to content

Commit c28a919

Browse files
committed
fix(runtime-core): fix globalProperties in check on instance render proxy
1 parent 4d19636 commit c28a919

File tree

2 files changed

+85
-24
lines changed

2 files changed

+85
-24
lines changed

packages/runtime-core/__tests__/componentProxy.spec.ts

+42-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { h, render, getCurrentInstance, nodeOps } from '@vue/runtime-test'
1+
import {
2+
h,
3+
render,
4+
getCurrentInstance,
5+
nodeOps,
6+
createApp
7+
} from '@vue/runtime-test'
28
import { mockWarn } from '@vue/shared'
39
import { ComponentInternalInstance } from '../src/component'
410

@@ -137,6 +143,33 @@ describe('component: proxy', () => {
137143
expect(instance!.sink.foo).toBe(1)
138144
})
139145

146+
test('globalProperties', () => {
147+
let instance: ComponentInternalInstance
148+
let instanceProxy: any
149+
const Comp = {
150+
setup() {
151+
return () => null
152+
},
153+
mounted() {
154+
instance = getCurrentInstance()!
155+
instanceProxy = this
156+
}
157+
}
158+
159+
const app = createApp(Comp)
160+
app.config.globalProperties.foo = 1
161+
app.mount(nodeOps.createElement('div'))
162+
163+
expect(instanceProxy.foo).toBe(1)
164+
165+
// set should overwrite globalProperties with local
166+
instanceProxy.foo = 2
167+
expect(instanceProxy.foo).toBe(2)
168+
expect(instance!.sink.foo).toBe(2)
169+
// should not affect global
170+
expect(app.config.globalProperties.foo).toBe(1)
171+
})
172+
140173
test('has check', () => {
141174
let instanceProxy: any
142175
const Comp = {
@@ -158,7 +191,11 @@ describe('component: proxy', () => {
158191
instanceProxy = this
159192
}
160193
}
161-
render(h(Comp, { msg: 'hello' }), nodeOps.createElement('div'))
194+
195+
const app = createApp(Comp, { msg: 'hello' })
196+
app.config.globalProperties.global = 1
197+
198+
app.mount(nodeOps.createElement('div'))
162199

163200
// props
164201
expect('msg' in instanceProxy).toBe(true)
@@ -168,6 +205,8 @@ describe('component: proxy', () => {
168205
expect('bar' in instanceProxy).toBe(true)
169206
// public properties
170207
expect('$el' in instanceProxy).toBe(true)
208+
// global properties
209+
expect('global' in instanceProxy).toBe(true)
171210

172211
// non-existent
173212
expect('$foobar' in instanceProxy).toBe(false)
@@ -178,6 +217,7 @@ describe('component: proxy', () => {
178217
expect('baz' in instanceProxy).toBe(true)
179218

180219
// dev mode ownKeys check for console inspection
220+
// should only expose own keys
181221
expect(Object.keys(instanceProxy)).toMatchObject([
182222
'msg',
183223
'bar',

packages/runtime-core/src/componentProxy.ts

+43-22
Original file line numberDiff line numberDiff line change
@@ -159,22 +159,6 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
159159
}
160160
},
161161

162-
has(
163-
{
164-
_: { data, accessCache, renderContext, type, sink }
165-
}: ComponentPublicProxyTarget,
166-
key: string
167-
) {
168-
return (
169-
accessCache![key] !== undefined ||
170-
(data !== EMPTY_OBJ && hasOwn(data, key)) ||
171-
hasOwn(renderContext, key) ||
172-
(type.props && hasOwn(normalizePropsOptions(type.props)[0], key)) ||
173-
hasOwn(publicPropertiesMap, key) ||
174-
hasOwn(sink, key)
175-
)
176-
},
177-
178162
set(
179163
{ _: instance }: ComponentPublicProxyTarget,
180164
key: string,
@@ -207,6 +191,35 @@ export const PublicInstanceProxyHandlers: ProxyHandler<any> = {
207191
}
208192
}
209193
return true
194+
},
195+
196+
has(
197+
{
198+
_: { data, accessCache, renderContext, type, sink, appContext }
199+
}: ComponentPublicProxyTarget,
200+
key: string
201+
) {
202+
return (
203+
accessCache![key] !== undefined ||
204+
(data !== EMPTY_OBJ && hasOwn(data, key)) ||
205+
hasOwn(renderContext, key) ||
206+
(type.props && hasOwn(normalizePropsOptions(type.props)[0], key)) ||
207+
hasOwn(publicPropertiesMap, key) ||
208+
hasOwn(sink, key) ||
209+
hasOwn(appContext.config.globalProperties, key)
210+
)
211+
}
212+
}
213+
214+
if (__DEV__ && !__TEST__) {
215+
PublicInstanceProxyHandlers.ownKeys = (
216+
target: ComponentPublicProxyTarget
217+
) => {
218+
warn(
219+
`Avoid app logic that relies on enumerating keys on a component instance. ` +
220+
`The keys will be empty in production mode to avoid performance overhead.`
221+
)
222+
return Reflect.ownKeys(target)
210223
}
211224
}
212225

@@ -232,21 +245,31 @@ export function createDevProxyTarget(instance: ComponentInternalInstance) {
232245

233246
// expose internal instance for proxy handlers
234247
Object.defineProperty(target, `_`, {
248+
configurable: true,
249+
enumerable: false,
235250
get: () => instance
236251
})
237252

238253
// expose public properties
239254
Object.keys(publicPropertiesMap).forEach(key => {
240255
Object.defineProperty(target, key, {
241-
get: () => publicPropertiesMap[key](instance)
256+
configurable: true,
257+
enumerable: false,
258+
get: () => publicPropertiesMap[key](instance),
259+
// intercepted by the proxy so no need for implementation,
260+
// but needed to prevent set errors
261+
set: NOOP
242262
})
243263
})
244264

245265
// expose global properties
246266
const { globalProperties } = instance.appContext.config
247267
Object.keys(globalProperties).forEach(key => {
248268
Object.defineProperty(target, key, {
249-
get: () => globalProperties[key]
269+
configurable: true,
270+
enumerable: false,
271+
get: () => globalProperties[key],
272+
set: NOOP
250273
})
251274
})
252275

@@ -264,9 +287,8 @@ export function exposePropsOnDevProxyTarget(
264287
Object.keys(normalizePropsOptions(propsOptions)[0]).forEach(key => {
265288
Object.defineProperty(proxyTarget, key, {
266289
enumerable: true,
290+
configurable: true,
267291
get: () => instance.props[key],
268-
// intercepted by the proxy so no need for implementation,
269-
// but needed to prevent set errors
270292
set: NOOP
271293
})
272294
})
@@ -280,9 +302,8 @@ export function exposeRenderContextOnDevProxyTarget(
280302
Object.keys(toRaw(renderContext)).forEach(key => {
281303
Object.defineProperty(proxyTarget, key, {
282304
enumerable: true,
305+
configurable: true,
283306
get: () => renderContext[key],
284-
// intercepted by the proxy so no need for implementation,
285-
// but needed to prevent set errors
286307
set: NOOP
287308
})
288309
})

0 commit comments

Comments
 (0)