Skip to content

Commit 14fcced

Browse files
authored
fix(runtime-core): avoid script setup bindings overwriting reserved ctx properties (#4570)
1 parent a31303f commit 14fcced

File tree

2 files changed

+64
-14
lines changed

2 files changed

+64
-14
lines changed

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

+48
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,54 @@ describe('api: createApp', () => {
482482
expect(serializeInner(root)).toBe('hello')
483483
})
484484

485+
test('return property "_" should not overwrite "ctx._", __isScriptSetup: false', () => {
486+
const Comp = defineComponent({
487+
setup() {
488+
return {
489+
_: ref(0) // return property "_" should not overwrite "ctx._"
490+
}
491+
},
492+
render() {
493+
return h('input', {
494+
ref: 'input'
495+
})
496+
}
497+
})
498+
499+
const root1 = nodeOps.createElement('div')
500+
createApp(Comp).mount(root1)
501+
502+
expect(
503+
`setup() return property "_" should not start with "$" or "_" which are reserved prefixes for Vue internals.`
504+
).toHaveBeenWarned()
505+
})
506+
507+
test('return property "_" should not overwrite "ctx._", __isScriptSetup: true', () => {
508+
const Comp = defineComponent({
509+
setup() {
510+
return {
511+
_: ref(0), // return property "_" should not overwrite "ctx._"
512+
__isScriptSetup: true // mock __isScriptSetup = true
513+
}
514+
},
515+
render() {
516+
return h('input', {
517+
ref: 'input'
518+
})
519+
}
520+
})
521+
522+
const root1 = nodeOps.createElement('div')
523+
const app = createApp(Comp).mount(root1)
524+
525+
// trigger
526+
app.$refs.input
527+
528+
expect(
529+
`TypeError: Cannot read property '__isScriptSetup' of undefined`
530+
).not.toHaveBeenWarned()
531+
})
532+
485533
// config.compilerOptions is tested in packages/vue since it is only
486534
// supported in the full build.
487535
})

packages/runtime-core/src/componentPublicInstance.ts

+16-14
Original file line numberDiff line numberDiff line change
@@ -538,20 +538,22 @@ export function exposeSetupStateOnRenderContext(
538538
) {
539539
const { ctx, setupState } = instance
540540
Object.keys(toRaw(setupState)).forEach(key => {
541-
if (!setupState.__isScriptSetup && (key[0] === '$' || key[0] === '_')) {
542-
warn(
543-
`setup() return property ${JSON.stringify(
544-
key
545-
)} should not start with "$" or "_" ` +
546-
`which are reserved prefixes for Vue internals.`
547-
)
548-
return
541+
if (!setupState.__isScriptSetup) {
542+
if (key[0] === '$' || key[0] === '_') {
543+
warn(
544+
`setup() return property ${JSON.stringify(
545+
key
546+
)} should not start with "$" or "_" ` +
547+
`which are reserved prefixes for Vue internals.`
548+
)
549+
return
550+
}
551+
Object.defineProperty(ctx, key, {
552+
enumerable: true,
553+
configurable: true,
554+
get: () => setupState[key],
555+
set: NOOP
556+
})
549557
}
550-
Object.defineProperty(ctx, key, {
551-
enumerable: true,
552-
configurable: true,
553-
get: () => setupState[key],
554-
set: NOOP
555-
})
556558
})
557559
}

0 commit comments

Comments
 (0)