]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): avoid mutating EMPTY_ARR when setting dev root (#2419)
author被雨水过滤的空气 <958414905@qq.com>
Mon, 19 Oct 2020 22:08:54 +0000 (06:08 +0800)
committerGitHub <noreply@github.com>
Mon, 19 Oct 2020 22:08:54 +0000 (18:08 -0400)
also freeze EMPTY_ARR in dev

fix #2413

packages/runtime-core/src/componentProps.ts
packages/runtime-core/src/componentRenderUtils.ts
packages/runtime-core/src/vnode.ts
packages/shared/src/index.ts
packages/vue/__tests__/index.spec.ts

index f1be9b76961e6a11b7f88d6f10a1d6fc29d1d1c0..47b0645950595becd841aa82e97fdf55a009e998 100644 (file)
@@ -378,7 +378,7 @@ export function normalizePropsOptions(
   }
 
   if (!raw && !hasExtends) {
-    return (comp.__props = EMPTY_ARR)
+    return (comp.__props = EMPTY_ARR as any)
   }
 
   if (isArray(raw)) {
index 39f53603c5697526e0659ce00e2420a20e42bf2b..a3da6e0ff4f2b589ad7b3cee9af9fb5fadb16c96 100644 (file)
@@ -226,7 +226,7 @@ const getChildRoot = (
     return [vnode, undefined]
   }
   const rawChildren = vnode.children as VNodeArrayChildren
-  const dynamicChildren = vnode.dynamicChildren as VNodeArrayChildren
+  const dynamicChildren = vnode.dynamicChildren
   const childRoot = filterSingleRoot(rawChildren)
   if (!childRoot) {
     return [vnode, undefined]
@@ -235,10 +235,12 @@ const getChildRoot = (
   const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1
   const setRoot = (updatedRoot: VNode) => {
     rawChildren[index] = updatedRoot
-    if (dynamicIndex > -1) {
-      dynamicChildren[dynamicIndex] = updatedRoot
-    } else if (dynamicChildren && updatedRoot.patchFlag > 0) {
-      dynamicChildren.push(updatedRoot)
+    if (dynamicChildren) {
+      if (dynamicIndex > -1) {
+        dynamicChildren[dynamicIndex] = updatedRoot
+      } else if (updatedRoot.patchFlag > 0) {
+        vnode.dynamicChildren = [...dynamicChildren, updatedRoot]
+      }
     }
   }
   return [normalizeVNode(childRoot), setRoot]
index 8be4314d5bb771eadd43fff307a43c9fcd6c792e..88fca729634761dff38f6e176cb849eaf27f103d 100644 (file)
@@ -243,7 +243,7 @@ export function createBlock(
     true /* isBlock: prevent a block from tracking itself */
   )
   // save current block children on the block vnode
-  vnode.dynamicChildren = currentBlock || EMPTY_ARR
+  vnode.dynamicChildren = currentBlock || (EMPTY_ARR as any)
   // close block
   closeBlock()
   // a block is always going to be patched, so track it as a child of its
index fb355ac399a16121ad01ab46e758bea6aaed0261..84b324beda3511e50f9e764a460e1b75fff0e30c 100644 (file)
@@ -28,7 +28,7 @@ export const babelParserDefaultPlugins = [
 export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
   ? Object.freeze({})
   : {}
-export const EMPTY_ARR: [] = []
+export const EMPTY_ARR = __DEV__ ? Object.freeze([]) : []
 
 export const NOOP = () => {}
 
index 18c1c182e5a55c0554db060a6416a9ca4d17f18d..ae1f35bc259aa68741fc8841e04f0aeef06b0313 100644 (file)
@@ -1,3 +1,4 @@
+import { EMPTY_ARR } from '@vue/shared'
 import { createApp, ref, nextTick, reactive } from '../src'
 
 describe('compiler + runtime integration', () => {
@@ -281,4 +282,14 @@ describe('compiler + runtime integration', () => {
     await nextTick()
     expect(container.innerHTML).toBe(`<div>2<div>1</div></div>`)
   })
+
+  // #2413
+  it('EMPTY_ARR should not change', () => {
+    const App = {
+      template: `<div v-for="v of ['a']">{{ v }}</div>`
+    }
+    const container = document.createElement('div')
+    createApp(App).mount(container)
+    expect(EMPTY_ARR.length).toBe(0)
+  })
 })