Skip to content

Commit edd49dc

Browse files
authored
fix(runtime-core): avoid mutating EMPTY_ARR when setting dev root (#2419)
also freeze EMPTY_ARR in dev fix #2413
1 parent e894caf commit edd49dc

File tree

5 files changed

+21
-8
lines changed

5 files changed

+21
-8
lines changed

packages/runtime-core/src/componentProps.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ export function normalizePropsOptions(
378378
}
379379

380380
if (!raw && !hasExtends) {
381-
return (comp.__props = EMPTY_ARR)
381+
return (comp.__props = EMPTY_ARR as any)
382382
}
383383

384384
if (isArray(raw)) {

packages/runtime-core/src/componentRenderUtils.ts

+7-5
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ const getChildRoot = (
226226
return [vnode, undefined]
227227
}
228228
const rawChildren = vnode.children as VNodeArrayChildren
229-
const dynamicChildren = vnode.dynamicChildren as VNodeArrayChildren
229+
const dynamicChildren = vnode.dynamicChildren
230230
const childRoot = filterSingleRoot(rawChildren)
231231
if (!childRoot) {
232232
return [vnode, undefined]
@@ -235,10 +235,12 @@ const getChildRoot = (
235235
const dynamicIndex = dynamicChildren ? dynamicChildren.indexOf(childRoot) : -1
236236
const setRoot = (updatedRoot: VNode) => {
237237
rawChildren[index] = updatedRoot
238-
if (dynamicIndex > -1) {
239-
dynamicChildren[dynamicIndex] = updatedRoot
240-
} else if (dynamicChildren && updatedRoot.patchFlag > 0) {
241-
dynamicChildren.push(updatedRoot)
238+
if (dynamicChildren) {
239+
if (dynamicIndex > -1) {
240+
dynamicChildren[dynamicIndex] = updatedRoot
241+
} else if (updatedRoot.patchFlag > 0) {
242+
vnode.dynamicChildren = [...dynamicChildren, updatedRoot]
243+
}
242244
}
243245
}
244246
return [normalizeVNode(childRoot), setRoot]

packages/runtime-core/src/vnode.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ export function createBlock(
243243
true /* isBlock: prevent a block from tracking itself */
244244
)
245245
// save current block children on the block vnode
246-
vnode.dynamicChildren = currentBlock || EMPTY_ARR
246+
vnode.dynamicChildren = currentBlock || (EMPTY_ARR as any)
247247
// close block
248248
closeBlock()
249249
// a block is always going to be patched, so track it as a child of its

packages/shared/src/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export const babelParserDefaultPlugins = [
2828
export const EMPTY_OBJ: { readonly [key: string]: any } = __DEV__
2929
? Object.freeze({})
3030
: {}
31-
export const EMPTY_ARR: [] = []
31+
export const EMPTY_ARR = __DEV__ ? Object.freeze([]) : []
3232

3333
export const NOOP = () => {}
3434

packages/vue/__tests__/index.spec.ts

+11
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { EMPTY_ARR } from '@vue/shared'
12
import { createApp, ref, nextTick, reactive } from '../src'
23

34
describe('compiler + runtime integration', () => {
@@ -281,4 +282,14 @@ describe('compiler + runtime integration', () => {
281282
await nextTick()
282283
expect(container.innerHTML).toBe(`<div>2<div>1</div></div>`)
283284
})
285+
286+
// #2413
287+
it('EMPTY_ARR should not change', () => {
288+
const App = {
289+
template: `<div v-for="v of ['a']">{{ v }}</div>`
290+
}
291+
const container = document.createElement('div')
292+
createApp(App).mount(container)
293+
expect(EMPTY_ARR.length).toBe(0)
294+
})
284295
})

0 commit comments

Comments
 (0)