From 14fcced281c5de2f07629a8028653cab1e787b89 Mon Sep 17 00:00:00 2001 From: ygj6 <7699524+ygj6@users.noreply.github.com> Date: Thu, 16 Sep 2021 23:16:07 +0800 Subject: [PATCH] fix(runtime-core): avoid script setup bindings overwriting reserved ctx properties (#4570) --- .../__tests__/apiCreateApp.spec.ts | 48 +++++++++++++++++++ .../src/componentPublicInstance.ts | 30 ++++++------ 2 files changed, 64 insertions(+), 14 deletions(-) diff --git a/packages/runtime-core/__tests__/apiCreateApp.spec.ts b/packages/runtime-core/__tests__/apiCreateApp.spec.ts index 3dfc040b707..e5e9a5906b1 100644 --- a/packages/runtime-core/__tests__/apiCreateApp.spec.ts +++ b/packages/runtime-core/__tests__/apiCreateApp.spec.ts @@ -482,6 +482,54 @@ describe('api: createApp', () => { expect(serializeInner(root)).toBe('hello') }) + test('return property "_" should not overwrite "ctx._", __isScriptSetup: false', () => { + const Comp = defineComponent({ + setup() { + return { + _: ref(0) // return property "_" should not overwrite "ctx._" + } + }, + render() { + return h('input', { + ref: 'input' + }) + } + }) + + const root1 = nodeOps.createElement('div') + createApp(Comp).mount(root1) + + expect( + `setup() return property "_" should not start with "$" or "_" which are reserved prefixes for Vue internals.` + ).toHaveBeenWarned() + }) + + test('return property "_" should not overwrite "ctx._", __isScriptSetup: true', () => { + const Comp = defineComponent({ + setup() { + return { + _: ref(0), // return property "_" should not overwrite "ctx._" + __isScriptSetup: true // mock __isScriptSetup = true + } + }, + render() { + return h('input', { + ref: 'input' + }) + } + }) + + const root1 = nodeOps.createElement('div') + const app = createApp(Comp).mount(root1) + + // trigger + app.$refs.input + + expect( + `TypeError: Cannot read property '__isScriptSetup' of undefined` + ).not.toHaveBeenWarned() + }) + // config.compilerOptions is tested in packages/vue since it is only // supported in the full build. }) diff --git a/packages/runtime-core/src/componentPublicInstance.ts b/packages/runtime-core/src/componentPublicInstance.ts index aad6207ec46..dd385a815c9 100644 --- a/packages/runtime-core/src/componentPublicInstance.ts +++ b/packages/runtime-core/src/componentPublicInstance.ts @@ -538,20 +538,22 @@ export function exposeSetupStateOnRenderContext( ) { const { ctx, setupState } = instance Object.keys(toRaw(setupState)).forEach(key => { - if (!setupState.__isScriptSetup && (key[0] === '$' || key[0] === '_')) { - warn( - `setup() return property ${JSON.stringify( - key - )} should not start with "$" or "_" ` + - `which are reserved prefixes for Vue internals.` - ) - return + if (!setupState.__isScriptSetup) { + if (key[0] === '$' || key[0] === '_') { + warn( + `setup() return property ${JSON.stringify( + key + )} should not start with "$" or "_" ` + + `which are reserved prefixes for Vue internals.` + ) + return + } + Object.defineProperty(ctx, key, { + enumerable: true, + configurable: true, + get: () => setupState[key], + set: NOOP + }) } - Object.defineProperty(ctx, key, { - enumerable: true, - configurable: true, - get: () => setupState[key], - set: NOOP - }) }) }