]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): Avoid mutating original options object in createApp (#4840)
authorYuchao <yuchaoyj@gmail.com>
Tue, 12 Apr 2022 07:14:23 +0000 (17:14 +1000)
committerGitHub <noreply@github.com>
Tue, 12 Apr 2022 07:14:23 +0000 (03:14 -0400)
fix #4398

packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-dom/__tests__/createApp.spec.ts

index 44434a256d52d6b9d112375c53ec762e5b1c88bb..fdcde4639fcfba87ae9e89e31db256333f68c7d9 100644 (file)
@@ -91,9 +91,9 @@ describe('resolveAssets', () => {
     const root = nodeOps.createElement('div')
     app.mount(root)
 
-    expect(component1!).toBe(Root) // explicit self name reference
+    expect(component1!).toMatchObject(Root) // explicit self name reference
     expect(component2!).toBe(Foo) // successful resolve take higher priority
-    expect(component3!).toBe(Root) // fallback when resolve fails
+    expect(component3!).toMatchObject(Root) // fallback when resolve fails
   })
 
   describe('warning', () => {
index ae2f58418dce7d2f333a3ca0fc90b875e56e621a..98eb8fc844ff96a2fb55e3a1555e43a52405aa1c 100644 (file)
@@ -179,6 +179,11 @@ export function createAppAPI<HostElement>(
   hydrate?: RootHydrateFunction
 ): CreateAppFunction<HostElement> {
   return function createApp(rootComponent, rootProps = null) {
+
+    if (!isFunction(rootComponent)) {
+      rootComponent = { ...rootComponent }
+    }
+
     if (rootProps != null && !isObject(rootProps)) {
       __DEV__ && warn(`root props passed to app.mount() must be an object.`)
       rootProps = null
index 00c9282e1b3107d738373186d154553ae71e3ebf..86b25f5c21166da1d015e13e1b787fdc36e5d9c4 100644 (file)
@@ -12,4 +12,33 @@ describe('createApp for dom', () => {
     expect(root.children.length).toBe(1)
     expect(root.children[0] instanceof SVGElement).toBe(true)
   })
+
+  // #4398
+  test('should not mutate original root component options object', () => {
+    
+    const originalObj =  {
+      data() {
+        return {
+          counter: 0
+        }
+      }
+    }
+
+    const handler = jest.fn(msg => {
+      expect(msg).toMatch(`Component is missing template or render function`)
+    })
+
+    const Root = { ...originalObj}
+    
+    const app = createApp(Root)
+    app.config.warnHandler = handler
+    app.mount(document.createElement('div')) 
+    // ensure mount is based on a copy of Root object rather than Root object itself 
+    expect(app._component).not.toBe(Root)
+    
+    // ensure no mutation happened to Root object
+    expect(originalObj).toMatchObject(Root)
+    
+  })
 })