Skip to content

Commit d121a9b

Browse files
authored
fix(runtime-core): Avoid mutating original options object in createApp (#4840)
fix #4398
1 parent 4311ddd commit d121a9b

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -91,9 +91,9 @@ describe('resolveAssets', () => {
9191
const root = nodeOps.createElement('div')
9292
app.mount(root)
9393

94-
expect(component1!).toBe(Root) // explicit self name reference
94+
expect(component1!).toMatchObject(Root) // explicit self name reference
9595
expect(component2!).toBe(Foo) // successful resolve take higher priority
96-
expect(component3!).toBe(Root) // fallback when resolve fails
96+
expect(component3!).toMatchObject(Root) // fallback when resolve fails
9797
})
9898

9999
describe('warning', () => {

packages/runtime-core/src/apiCreateApp.ts

+5
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,11 @@ export function createAppAPI<HostElement>(
179179
hydrate?: RootHydrateFunction
180180
): CreateAppFunction<HostElement> {
181181
return function createApp(rootComponent, rootProps = null) {
182+
183+
if (!isFunction(rootComponent)) {
184+
rootComponent = { ...rootComponent }
185+
}
186+
182187
if (rootProps != null && !isObject(rootProps)) {
183188
__DEV__ && warn(`root props passed to app.mount() must be an object.`)
184189
rootProps = null

packages/runtime-dom/__tests__/createApp.spec.ts

+29
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,33 @@ describe('createApp for dom', () => {
1212
expect(root.children.length).toBe(1)
1313
expect(root.children[0] instanceof SVGElement).toBe(true)
1414
})
15+
16+
// #4398
17+
test('should not mutate original root component options object', () => {
18+
19+
const originalObj = {
20+
data() {
21+
return {
22+
counter: 0
23+
}
24+
}
25+
}
26+
27+
const handler = jest.fn(msg => {
28+
expect(msg).toMatch(`Component is missing template or render function`)
29+
})
30+
31+
const Root = { ...originalObj}
32+
33+
const app = createApp(Root)
34+
app.config.warnHandler = handler
35+
app.mount(document.createElement('div'))
36+
37+
// ensure mount is based on a copy of Root object rather than Root object itself
38+
expect(app._component).not.toBe(Root)
39+
40+
// ensure no mutation happened to Root object
41+
expect(originalObj).toMatchObject(Root)
42+
43+
})
1544
})

0 commit comments

Comments
 (0)