Переглянути джерело

fix(runtime-core): avoid script setup bindings overwriting reserved ctx properties (#4570)

ygj6 4 роки тому
батько
коміт
14fcced281

+ 48 - 0
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.
 })

+ 16 - 14
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
-    })
   })
 }