]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor: adjust `createApp` related API signatures
authorEvan You <yyx990803@gmail.com>
Thu, 23 Jan 2020 20:05:38 +0000 (15:05 -0500)
committerEvan You <yyx990803@gmail.com>
Mon, 27 Jan 2020 21:00:17 +0000 (16:00 -0500)
BREAKING CHANGE: `createApp` API has been adjusted.

  - `createApp()` now accepts the root component, and optionally a props
  object to pass to the root component.
  - `app.mount()` now accepts a single argument (the root container)
  - `app.unmount()` no longer requires arguments.

  New behavior looks like the following:

  ``` js
  const app = createApp(RootComponent)
  app.mount('#app')
  app.unmount()
  ```

25 files changed:
packages/runtime-core/__tests__/apiCreateApp.spec.ts [moved from packages/runtime-core/__tests__/apiApp.spec.ts with 81% similarity]
packages/runtime-core/__tests__/componentProxy.spec.ts
packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts
packages/runtime-core/src/apiCreateApp.ts
packages/runtime-core/src/index.ts
packages/runtime-core/src/renderer.ts
packages/runtime-dom/__tests__/directives/vModel.spec.ts
packages/runtime-dom/__tests__/directives/vShow.spec.ts
packages/runtime-dom/src/index.ts
packages/runtime-test/src/index.ts
packages/vue/__tests__/index.spec.ts
packages/vue/examples/classic/commits.html
packages/vue/examples/classic/grid.html
packages/vue/examples/classic/markdown.html
packages/vue/examples/classic/svg.html
packages/vue/examples/classic/todomvc.html
packages/vue/examples/classic/tree.html
packages/vue/examples/composition/commits.html
packages/vue/examples/composition/grid.html
packages/vue/examples/composition/markdown.html
packages/vue/examples/composition/svg.html
packages/vue/examples/composition/todomvc.html
packages/vue/examples/composition/tree.html
packages/vue/examples/transition/list.html
packages/vue/examples/transition/modal.html

similarity index 81%
rename from packages/runtime-core/__tests__/apiApp.spec.ts
rename to packages/runtime-core/__tests__/apiCreateApp.spec.ts
index 6fb8239b8f9c6befe67560a21f4bc7b3f5d8ffa7..0442cf706269e7bd8b4258ec2471edb11566781b 100644 (file)
@@ -30,18 +30,18 @@ describe('api: createApp', () => {
     }
 
     const root1 = nodeOps.createElement('div')
-    createApp().mount(Comp, root1)
+    createApp(Comp).mount(root1)
     expect(serializeInner(root1)).toBe(`0`)
 
     // mount with props
     const root2 = nodeOps.createElement('div')
-    const app2 = createApp()
-    app2.mount(Comp, root2, { count: 1 })
+    const app2 = createApp(Comp, { count: 1 })
+    app2.mount(root2)
     expect(serializeInner(root2)).toBe(`1`)
 
     // remount warning
     const root3 = nodeOps.createElement('div')
-    app2.mount(Comp, root3)
+    app2.mount(root3)
     expect(serializeInner(root3)).toBe(``)
     expect(`already been mounted`).toHaveBeenWarned()
   })
@@ -59,18 +59,14 @@ describe('api: createApp', () => {
     }
 
     const root = nodeOps.createElement('div')
-    const app = createApp()
-    app.mount(Comp, root)
+    const app = createApp(Comp)
+    app.mount(root)
 
     app.unmount(root)
     expect(serializeInner(root)).toBe(``)
   })
 
   test('provide', () => {
-    const app = createApp()
-    app.provide('foo', 1)
-    app.provide('bar', 2)
-
     const Root = {
       setup() {
         // test override
@@ -87,25 +83,16 @@ describe('api: createApp', () => {
       }
     }
 
+    const app = createApp(Root)
+    app.provide('foo', 1)
+    app.provide('bar', 2)
+
     const root = nodeOps.createElement('div')
-    app.mount(Root, root)
+    app.mount(root)
     expect(serializeInner(root)).toBe(`3,2`)
   })
 
   test('component', () => {
-    const app = createApp()
-
-    const FooBar = () => 'foobar!'
-    app.component('FooBar', FooBar)
-    expect(app.component('FooBar')).toBe(FooBar)
-
-    app.component('BarBaz', () => 'barbaz!')
-
-    app.component('BarBaz', () => 'barbaz!')
-    expect(
-      'Component "BarBaz" has already been registered in target app.'
-    ).toHaveBeenWarnedTimes(1)
-
     const Root = {
       // local override
       components: {
@@ -122,33 +109,29 @@ describe('api: createApp', () => {
       }
     }
 
+    const app = createApp(Root)
+
+    const FooBar = () => 'foobar!'
+    app.component('FooBar', FooBar)
+    expect(app.component('FooBar')).toBe(FooBar)
+
+    app.component('BarBaz', () => 'barbaz!')
+
+    app.component('BarBaz', () => 'barbaz!')
+    expect(
+      'Component "BarBaz" has already been registered in target app.'
+    ).toHaveBeenWarnedTimes(1)
+
     const root = nodeOps.createElement('div')
-    app.mount(Root, root)
+    app.mount(root)
     expect(serializeInner(root)).toBe(`<div>foobar!barbaz-local!</div>`)
   })
 
   test('directive', () => {
-    const app = createApp()
-
     const spy1 = jest.fn()
     const spy2 = jest.fn()
     const spy3 = jest.fn()
 
-    const FooBar = { mounted: spy1 }
-    app.directive('FooBar', FooBar)
-    expect(app.directive('FooBar')).toBe(FooBar)
-
-    app.directive('BarBaz', {
-      mounted: spy2
-    })
-
-    app.directive('BarBaz', {
-      mounted: spy2
-    })
-    expect(
-      'Directive "BarBaz" has already been registered in target app.'
-    ).toHaveBeenWarnedTimes(1)
-
     const Root = {
       // local override
       directives: {
@@ -165,8 +148,25 @@ describe('api: createApp', () => {
       }
     }
 
+    const app = createApp(Root)
+
+    const FooBar = { mounted: spy1 }
+    app.directive('FooBar', FooBar)
+    expect(app.directive('FooBar')).toBe(FooBar)
+
+    app.directive('BarBaz', {
+      mounted: spy2
+    })
+
+    app.directive('BarBaz', {
+      mounted: spy2
+    })
+    expect(
+      'Directive "BarBaz" has already been registered in target app.'
+    ).toHaveBeenWarnedTimes(1)
+
     const root = nodeOps.createElement('div')
-    app.mount(Root, root)
+    app.mount(root)
     expect(spy1).toHaveBeenCalled()
     expect(spy2).not.toHaveBeenCalled()
     expect(spy3).toHaveBeenCalled()
@@ -232,7 +232,7 @@ describe('api: createApp', () => {
       }
     }
 
-    const app = createApp()
+    const app = createApp(Comp)
     app.mixin(mixinA)
     app.mixin(mixinB)
 
@@ -246,7 +246,7 @@ describe('api: createApp', () => {
     ).toHaveBeenWarnedTimes(1)
 
     const root = nodeOps.createElement('div')
-    app.mount(Comp, root)
+    app.mount(root)
 
     expect(serializeInner(root)).toBe(`123`)
     expect(calls).toEqual([
@@ -272,11 +272,6 @@ describe('api: createApp', () => {
     }
     const PluginD: any = undefined
 
-    const app = createApp()
-    app.use(PluginA)
-    app.use(PluginB, 1, 1)
-    app.use(PluginC)
-
     const Root = {
       setup() {
         const foo = inject('foo')
@@ -284,8 +279,14 @@ describe('api: createApp', () => {
         return () => `${foo},${bar}`
       }
     }
+
+    const app = createApp(Root)
+    app.use(PluginA)
+    app.use(PluginB, 1, 1)
+    app.use(PluginC)
+
     const root = nodeOps.createElement('div')
-    app.mount(Root, root)
+    app.mount(root)
     expect(serializeInner(root)).toBe(`1,2`)
 
     app.use(PluginA)
@@ -301,18 +302,14 @@ describe('api: createApp', () => {
   })
 
   test('config.errorHandler', () => {
-    const app = createApp()
-
     const error = new Error()
     const count = ref(0)
 
-    const handler = (app.config.errorHandler = jest.fn(
-      (err, instance, info) => {
-        expect(err).toBe(error)
-        expect((instance as any).count).toBe(count.value)
-        expect(info).toBe(`render function`)
-      }
-    ))
+    const handler = jest.fn((err, instance, info) => {
+      expect(err).toBe(error)
+      expect((instance as any).count).toBe(count.value)
+      expect(info).toBe(`render function`)
+    })
 
     const Root = {
       setup() {
@@ -326,21 +323,19 @@ describe('api: createApp', () => {
       }
     }
 
-    app.mount(Root, nodeOps.createElement('div'))
+    const app = createApp(Root)
+    app.config.errorHandler = handler
+    app.mount(nodeOps.createElement('div'))
     expect(handler).toHaveBeenCalled()
   })
 
   test('config.warnHandler', () => {
-    const app = createApp()
     let ctx: any
-
-    const handler = (app.config.warnHandler = jest.fn(
-      (msg, instance, trace) => {
-        expect(msg).toMatch(`Component is missing template or render function`)
-        expect(instance).toBe(ctx.proxy)
-        expect(trace).toMatch(`Hello`)
-      }
-    ))
+    const handler = jest.fn((msg, instance, trace) => {
+      expect(msg).toMatch(`Component is missing template or render function`)
+      expect(instance).toBe(ctx.proxy)
+      expect(trace).toMatch(`Hello`)
+    })
 
     const Root = {
       name: 'Hello',
@@ -349,7 +344,9 @@ describe('api: createApp', () => {
       }
     }
 
-    app.mount(Root, nodeOps.createElement('div'))
+    const app = createApp(Root)
+    app.config.warnHandler = handler
+    app.mount(nodeOps.createElement('div'))
     expect(handler).toHaveBeenCalledTimes(1)
   })
 
@@ -357,104 +354,82 @@ describe('api: createApp', () => {
     const isNativeTag = jest.fn(tag => tag === 'div')
 
     test('Component.name', () => {
-      const app = createApp()
-      Object.defineProperty(app.config, 'isNativeTag', {
-        value: isNativeTag,
-        writable: false
-      })
-
       const Root = {
         name: 'div',
-        setup() {
-          return {
-            count: ref(0)
-          }
-        },
         render() {
           return null
         }
       }
 
-      app.mount(Root, nodeOps.createElement('div'))
-      expect(
-        `Do not use built-in or reserved HTML elements as component id: div`
-      ).toHaveBeenWarned()
-    })
+      const app = createApp(Root)
 
-    test('Component.components', () => {
-      const app = createApp()
       Object.defineProperty(app.config, 'isNativeTag', {
         value: isNativeTag,
         writable: false
       })
 
+      app.mount(nodeOps.createElement('div'))
+      expect(
+        `Do not use built-in or reserved HTML elements as component id: div`
+      ).toHaveBeenWarned()
+    })
+
+    test('Component.components', () => {
       const Root = {
         components: {
           div: () => 'div'
         },
-        setup() {
-          return {
-            count: ref(0)
-          }
-        },
         render() {
           return null
         }
       }
 
-      app.mount(Root, nodeOps.createElement('div'))
+      const app = createApp(Root)
+      Object.defineProperty(app.config, 'isNativeTag', {
+        value: isNativeTag,
+        writable: false
+      })
+
+      app.mount(nodeOps.createElement('div'))
       expect(
         `Do not use built-in or reserved HTML elements as component id: div`
       ).toHaveBeenWarned()
     })
 
     test('Component.directives', () => {
-      const app = createApp()
-      Object.defineProperty(app.config, 'isNativeTag', {
-        value: isNativeTag,
-        writable: false
-      })
-
       const Root = {
         directives: {
           bind: () => {}
         },
-        setup() {
-          return {
-            count: ref(0)
-          }
-        },
         render() {
           return null
         }
       }
 
-      app.mount(Root, nodeOps.createElement('div'))
+      const app = createApp(Root)
+      Object.defineProperty(app.config, 'isNativeTag', {
+        value: isNativeTag,
+        writable: false
+      })
+
+      app.mount(nodeOps.createElement('div'))
       expect(
         `Do not use built-in directive ids as custom directive id: bind`
       ).toHaveBeenWarned()
     })
 
     test('register using app.component', () => {
-      const app = createApp()
+      const app = createApp({
+        render() {}
+      })
+
       Object.defineProperty(app.config, 'isNativeTag', {
         value: isNativeTag,
         writable: false
       })
 
-      const Root = {
-        setup() {
-          return {
-            count: ref(0)
-          }
-        },
-        render() {
-          return null
-        }
-      }
-
       app.component('div', () => 'div')
-      app.mount(Root, nodeOps.createElement('div'))
+      app.mount(nodeOps.createElement('div'))
       expect(
         `Do not use built-in or reserved HTML elements as component id: div`
       ).toHaveBeenWarned()
index ddfd8cab0bf8ed507510aea1e8f93d4617317bec..0790f2246e1c38523b4e2a4a0c0ff02907e3d0b1 100644 (file)
@@ -1,4 +1,4 @@
-import { createApp, getCurrentInstance, nodeOps } from '@vue/runtime-test'
+import { h, render, getCurrentInstance, nodeOps } from '@vue/runtime-test'
 import { mockWarn } from '@vue/shared'
 import { ComponentInternalInstance } from '../src/component'
 
@@ -6,7 +6,6 @@ describe('component: proxy', () => {
   mockWarn()
 
   test('data', () => {
-    const app = createApp()
     let instance: ComponentInternalInstance
     let instanceProxy: any
     const Comp = {
@@ -23,14 +22,13 @@ describe('component: proxy', () => {
         return null
       }
     }
-    app.mount(Comp, nodeOps.createElement('div'))
+    render(h(Comp), nodeOps.createElement('div'))
     expect(instanceProxy.foo).toBe(1)
     instanceProxy.foo = 2
     expect(instance!.data.foo).toBe(2)
   })
 
   test('renderContext', () => {
-    const app = createApp()
     let instance: ComponentInternalInstance
     let instanceProxy: any
     const Comp = {
@@ -47,14 +45,13 @@ describe('component: proxy', () => {
         return null
       }
     }
-    app.mount(Comp, nodeOps.createElement('div'))
+    render(h(Comp), nodeOps.createElement('div'))
     expect(instanceProxy.foo).toBe(1)
     instanceProxy.foo = 2
     expect(instance!.renderContext.foo).toBe(2)
   })
 
   test('propsProxy', () => {
-    const app = createApp()
     let instance: ComponentInternalInstance
     let instanceProxy: any
     const Comp = {
@@ -72,7 +69,7 @@ describe('component: proxy', () => {
         instanceProxy = this
       }
     }
-    app.mount(Comp, nodeOps.createElement('div'))
+    render(h(Comp), nodeOps.createElement('div'))
     expect(instanceProxy.foo).toBe(1)
     expect(instance!.propsProxy!.foo).toBe(1)
     expect(() => (instanceProxy.foo = 2)).toThrow(TypeError)
@@ -80,7 +77,6 @@ describe('component: proxy', () => {
   })
 
   test('public properties', () => {
-    const app = createApp()
     let instance: ComponentInternalInstance
     let instanceProxy: any
     const Comp = {
@@ -92,7 +88,7 @@ describe('component: proxy', () => {
         instanceProxy = this
       }
     }
-    app.mount(Comp, nodeOps.createElement('div'))
+    render(h(Comp), nodeOps.createElement('div'))
     expect(instanceProxy.$data).toBe(instance!.data)
     expect(instanceProxy.$props).toBe(instance!.propsProxy)
     expect(instanceProxy.$attrs).toBe(instance!.attrs)
@@ -108,7 +104,6 @@ describe('component: proxy', () => {
   })
 
   test('sink', async () => {
-    const app = createApp()
     let instance: ComponentInternalInstance
     let instanceProxy: any
     const Comp = {
@@ -120,14 +115,13 @@ describe('component: proxy', () => {
         instanceProxy = this
       }
     }
-    app.mount(Comp, nodeOps.createElement('div'))
+    render(h(Comp), nodeOps.createElement('div'))
     instanceProxy.foo = 1
     expect(instanceProxy.foo).toBe(1)
     expect(instance!.sink.foo).toBe(1)
   })
 
   test('has check', () => {
-    const app = createApp()
     let instanceProxy: any
     const Comp = {
       render() {},
@@ -148,7 +142,7 @@ describe('component: proxy', () => {
         instanceProxy = this
       }
     }
-    app.mount(Comp, nodeOps.createElement('div'), { msg: 'hello' })
+    render(h(Comp, { msg: 'hello' }), nodeOps.createElement('div'))
 
     // props
     expect('msg' in instanceProxy).toBe(true)
index 392311c1cb5f93fb0fc9e00c2be69ef66c37377c..779814b793001bdc9a22f8b228269b5f863ffb80 100644 (file)
@@ -12,7 +12,6 @@ import { mockWarn } from '@vue/shared'
 
 describe('resolveAssets', () => {
   test('should work', () => {
-    const app = createApp()
     const FooBar = () => null
     const BarBaz = { mounted: () => null }
 
@@ -49,8 +48,9 @@ describe('resolveAssets', () => {
       }
     }
 
+    const app = createApp(Root)
     const root = nodeOps.createElement('div')
-    app.mount(Root, root)
+    app.mount(root)
     expect(component1!).toBe(FooBar)
     expect(component2!).toBe(FooBar)
     expect(component3!).toBe(FooBar)
@@ -78,7 +78,6 @@ describe('resolveAssets', () => {
     })
 
     test('not exist', () => {
-      const app = createApp()
       const Root = {
         setup() {
           resolveComponent('foo')
@@ -87,14 +86,14 @@ describe('resolveAssets', () => {
         }
       }
 
+      const app = createApp(Root)
       const root = nodeOps.createElement('div')
-      app.mount(Root, root)
+      app.mount(root)
       expect('Failed to resolve component: foo').toHaveBeenWarned()
       expect('Failed to resolve directive: bar').toHaveBeenWarned()
     })
 
     test('resolve dynamic component', () => {
-      const app = createApp()
       const dynamicComponents = {
         foo: () => 'foo',
         bar: () => 'bar',
@@ -112,8 +111,10 @@ describe('resolveAssets', () => {
           }
         }
       }
+
+      const app = createApp(Root)
       const root = nodeOps.createElement('div')
-      app.mount(Root, root)
+      app.mount(root)
       expect(foo).toBe(dynamicComponents.foo)
       expect(bar).toBe(dynamicComponents.bar)
       expect(baz).toBe(dynamicComponents.baz)
index fdd377d02644723ea7473727d8fd88d4c2ecfe13..a01b5ecb6083d5eb8db946cee745a47ba00bc926 100644 (file)
@@ -16,16 +16,11 @@ export interface App<HostElement = any> {
   component(name: string, component: Component): this
   directive(name: string): Directive | undefined
   directive(name: string, directive: Directive): this
-  mount(
-    rootComponent:
-      | Component
-      // for compatibility with defineComponent() return types
-      | { new (): ComponentPublicInstance<any, any, any, any, any> },
-    rootContainer: HostElement | string,
-    rootProps?: Data
-  ): ComponentPublicInstance
+  mount(rootContainer: HostElement | string): ComponentPublicInstance
   unmount(rootContainer: HostElement | string): void
   provide<T>(key: InjectionKey<T> | string, value: T): this
+  rootComponent: Component
+  rootContainer: HostElement | null
 }
 
 export interface AppConfig {
@@ -79,16 +74,30 @@ export function createAppContext(): AppContext {
   }
 }
 
+export type CreateAppFunction<HostElement> = (
+  rootComponent:
+    | Component
+    // for compatibility with defineComponent() return types
+    | { new (): ComponentPublicInstance<any, any, any, any, any> },
+  rootProps?: Data | null
+) => App<HostElement>
+
 export function createAppAPI<HostNode, HostElement>(
   render: RootRenderFunction<HostNode, HostElement>
-): () => App<HostElement> {
-  return function createApp(): App {
+): CreateAppFunction<HostElement> {
+  return function createApp(
+    rootComponent: Component,
+    rootProps?: Data | null
+  ): App {
     const context = createAppContext()
     const installedPlugins = new Set()
 
     let isMounted = false
 
     const app: App = {
+      rootComponent,
+      rootContainer: null,
+
       get config() {
         return context.config
       },
@@ -165,11 +174,7 @@ export function createAppAPI<HostNode, HostElement>(
         return app
       },
 
-      mount(
-        rootComponent: Component,
-        rootContainer: HostElement,
-        rootProps?: Data | null
-      ): any {
+      mount(rootContainer: HostElement): any {
         if (!isMounted) {
           if (rootProps != null && !isObject(rootProps)) {
             __DEV__ &&
@@ -190,6 +195,7 @@ export function createAppAPI<HostNode, HostElement>(
 
           render(vnode, rootContainer)
           isMounted = true
+          app.rootContainer = rootContainer
           return vnode.component!.proxy
         } else if (__DEV__) {
           warn(
@@ -198,8 +204,12 @@ export function createAppAPI<HostNode, HostElement>(
         }
       },
 
-      unmount(rootContainer: HostElement) {
-        render(null, rootContainer)
+      unmount() {
+        if (isMounted) {
+          render(null, app.rootContainer!)
+        } else if (__DEV__) {
+          warn(`Cannot unmount an app that is not mounted.`)
+        }
       },
 
       provide(key, value) {
index 181e53f8dd28e78715e98e85236c0f23f479335c..435ede78176dfba6591e839acd6d0014a870afb6 100644 (file)
@@ -99,7 +99,13 @@ export { registerRuntimeCompiler } from './component'
 
 // Types -----------------------------------------------------------------------
 
-export { App, AppConfig, AppContext, Plugin } from './apiCreateApp'
+export {
+  App,
+  AppConfig,
+  AppContext,
+  Plugin,
+  CreateAppFunction
+} from './apiCreateApp'
 export { VNode, VNodeTypes, VNodeProps } from './vnode'
 export {
   Component,
index d26f73dae9a0f0cf303f81b6be40af3f306cccce..7af49a21d93f6d73a25251cce40cba8ba9558595 100644 (file)
@@ -46,7 +46,7 @@ import { ShapeFlags } from './shapeFlags'
 import { pushWarningContext, popWarningContext, warn } from './warning'
 import { invokeDirectiveHook } from './directives'
 import { ComponentPublicInstance } from './componentProxy'
-import { App, createAppAPI } from './apiCreateApp'
+import { createAppAPI, CreateAppFunction } from './apiCreateApp'
 import {
   SuspenseBoundary,
   queueEffectWithSuspense,
@@ -174,7 +174,7 @@ export function createRenderer<
   options: RendererOptions<HostNode, HostElement>
 ): {
   render: RootRenderFunction<HostNode, HostElement>
-  createApp: () => App<HostElement>
+  createApp: CreateAppFunction<HostElement>
 } {
   type HostVNode = VNode<HostNode, HostElement>
   type HostVNodeChildren = VNodeChildren<HostNode, HostElement>
index cd187ff80af949662022470f03ec0b82dee829b1..aac67c00d2db56ab0fa291e65c547c3cfe47774b 100644 (file)
@@ -1,6 +1,6 @@
 import {
-  createApp,
   h,
+  render,
   nextTick,
   defineComponent,
   vModelDynamic,
@@ -20,10 +20,9 @@ const setValue = function(this: any, value: any) {
   this.value = value
 }
 
-let app: any, root: any
+let root: any
 
 beforeEach(() => {
-  app = createApp()
   root = document.createElement('div') as any
 })
 
@@ -44,9 +43,9 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
-    const input = root.querySelector('input')
+    const input = root.querySelector('input')!
     const data = root._vnode.component.data
 
     input.value = 'foo'
@@ -75,7 +74,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const input = root.querySelector('textarea')
     const data = root._vnode.component.data
@@ -136,7 +135,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const number = root.querySelector('.number')
     const trim = root.querySelector('.trim')
@@ -176,7 +175,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const input = root.querySelector('input')
     const data = root._vnode.component.data
@@ -219,7 +218,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const input = root.querySelector('input')
     const data = root._vnode.component.data
@@ -262,7 +261,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const input = root.querySelector('input')
     const data = root._vnode.component.data
@@ -314,7 +313,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const foo = root.querySelector('.foo')
     const bar = root.querySelector('.bar')
@@ -384,7 +383,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const foo = root.querySelector('.foo')
     const bar = root.querySelector('.bar')
@@ -437,7 +436,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const input = root.querySelector('select')
     const foo = root.querySelector('option[value=foo]')
@@ -494,7 +493,7 @@ describe('vModel', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const input = root.querySelector('select')
     const foo = root.querySelector('option[value=foo]')
index 76eef6513e4f40acf1e8d92f050a33a175e0dcab..6c21e5f83f07b42bf48532b9d1b87b052fba1662 100644 (file)
@@ -5,16 +5,15 @@ import {
   nextTick,
   VNode
 } from '@vue/runtime-core'
-import { createApp, vShow } from '@vue/runtime-dom'
+import { render, vShow } from '@vue/runtime-dom'
 
 const withVShow = (node: VNode, exp: any) =>
   withDirectives(node, [[vShow, exp]])
 
-let app: any, root: any
+let root: any
 
 beforeEach(() => {
-  app = createApp()
-  root = document.createElement('div') as any
+  root = document.createElement('div')
 })
 
 describe('runtime-dom: v-show directive', () => {
@@ -27,7 +26,7 @@ describe('runtime-dom: v-show directive', () => {
         return [withVShow(h('div'), this.value)]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const $div = root.querySelector('div')
 
@@ -43,7 +42,7 @@ describe('runtime-dom: v-show directive', () => {
         return [withVShow(h('div'), this.value)]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const $div = root.querySelector('div')
 
@@ -59,7 +58,7 @@ describe('runtime-dom: v-show directive', () => {
         return [withVShow(h('div'), this.value)]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const $div = root.querySelector('div')
     const data = root._vnode.component.data
@@ -110,7 +109,7 @@ describe('runtime-dom: v-show directive', () => {
         ]
       }
     })
-    app.mount(component, root)
+    render(h(component), root)
 
     const $div = root.querySelector('div')
     const data = root._vnode.component.data
index 8d5de566483ead73dc1d2266f2067754a9dd61a8..51a8e0aa53daacfbe314eb79afd19ab75d99d5e5 100644 (file)
@@ -1,8 +1,8 @@
 import {
   createRenderer,
   warn,
-  App,
-  RootRenderFunction
+  RootRenderFunction,
+  CreateAppFunction
 } from '@vue/runtime-core'
 import { nodeOps } from './nodeOps'
 import { patchProp } from './patchProp'
@@ -17,8 +17,8 @@ const { render: baseRender, createApp: baseCreateApp } = createRenderer({
 // use explicit type casts here to avoid import() calls in rolled-up d.ts
 export const render = baseRender as RootRenderFunction<Node, Element>
 
-export const createApp = (): App<Element> => {
-  const app = baseCreateApp()
+export const createApp: CreateAppFunction<Element> = (...args) => {
+  const app = baseCreateApp(...args)
 
   if (__DEV__) {
     // Inject `isNativeTag`
@@ -29,8 +29,8 @@ export const createApp = (): App<Element> => {
     })
   }
 
-  const { mount, unmount } = app
-  app.mount = (component, container, props): any => {
+  const { mount } = app
+  app.mount = (container): any => {
     if (isString(container)) {
       container = document.querySelector(container)!
       if (!container) {
@@ -39,6 +39,7 @@ export const createApp = (): App<Element> => {
         return
       }
     }
+    const component = app.rootComponent
     if (
       __RUNTIME_COMPILE__ &&
       !isFunction(component) &&
@@ -49,19 +50,7 @@ export const createApp = (): App<Element> => {
     }
     // clear content before mounting
     container.innerHTML = ''
-    return mount(component, container, props)
-  }
-
-  app.unmount = container => {
-    if (isString(container)) {
-      container = document.querySelector(container)!
-      if (!container) {
-        __DEV__ &&
-          warn(`Failed to unmount app: mount target selector returned null.`)
-        return
-      }
-    }
-    unmount(container)
+    return mount(container)
   }
 
   return app
index c057da7e018192e5ff705c1cf02055a1b24beca0..7b6dcfd97e2eeb6b7fea9471f6592dcb15ece0d1 100644 (file)
@@ -2,7 +2,7 @@ import {
   createRenderer,
   VNode,
   RootRenderFunction,
-  App
+  CreateAppFunction
 } from '@vue/runtime-core'
 import { nodeOps, TestNode, TestElement } from './nodeOps'
 import { patchProp } from './patchProp'
@@ -14,7 +14,7 @@ const { render: baseRender, createApp: baseCreateApp } = createRenderer({
 })
 
 export const render = baseRender as RootRenderFunction<TestNode, TestElement>
-export const createApp = baseCreateApp as () => App<TestElement>
+export const createApp = baseCreateApp as CreateAppFunction<TestElement>
 
 // convenience for one-off render validations
 export function renderToString(vnode: VNode) {
index 4a7a06bb64d1454e0f5c51899d362f21e05fc940..3bde76341e856743e825352b98e250ad7fc4b55b 100644 (file)
@@ -14,7 +14,7 @@ describe('compiler + runtime integration', () => {
         }
       }
     }
-    createApp().mount(App, container)
+    createApp(App).mount(container)
     expect(container.innerHTML).toBe(`0`)
   })
 
@@ -33,7 +33,7 @@ describe('compiler + runtime integration', () => {
         }
       }
     }
-    createApp().mount(App, container)
+    createApp(App).mount(container)
     expect(container.innerHTML).toBe(`0`)
   })
 
@@ -51,7 +51,7 @@ describe('compiler + runtime integration', () => {
         }
       }
     }
-    createApp().mount(App, container)
+    createApp(App).mount(container)
     expect(container.innerHTML).toBe(`0`)
   })
 
@@ -60,7 +60,7 @@ describe('compiler + runtime integration', () => {
     const App = {
       template: `<div v-if>`
     }
-    createApp().mount(App, container)
+    createApp(App).mount(container)
     expect(
       `Template compilation error: Element is missing end tag`
     ).toHaveBeenWarned()
@@ -78,26 +78,24 @@ describe('compiler + runtime integration', () => {
   })
 
   it('should support custom element', () => {
-    const app = createApp()
-    const container = document.createElement('div')
-    const App = {
+    const app = createApp({
       template: '<custom></custom>'
-    }
+    })
+    const container = document.createElement('div')
     app.config.isCustomElement = tag => tag === 'custom'
-    app.mount(App, container)
+    app.mount(container)
     expect(container.innerHTML).toBe('<custom></custom>')
   })
 
   it('should support using element innerHTML as template', () => {
-    const app = createApp()
-    const container = document.createElement('div')
-    container.innerHTML = '{{msg}}'
-    const App = {
+    const app = createApp({
       data: {
         msg: 'hello'
       }
-    }
-    app.mount(App, container)
+    })
+    const container = document.createElement('div')
+    container.innerHTML = '{{msg}}'
+    app.mount(container)
     expect(container.innerHTML).toBe('hello')
   })
 })
index d88f0e28b25e8df322075678bfdcedaa334579e8..1a2587538745e727dd829ca3a13ec5e0eb725101 100644 (file)
 <script>
 const API_URL = `https://api.github.com/repos/vuejs/vue-next/commits?per_page=3&sha=`
 
-const App = {
-  data: {
+Vue.createApp({
+  data: () => ({
     branches: ['master', 'sync'],
     currentBranch: 'master',
     commits: null
-  },
+  }),
 
   created() {
     this.fetchData()
@@ -55,9 +55,7 @@ const App = {
       return v.replace(/T|Z/g, ' ')
     }
   }
-}
-
-Vue.createApp().mount(App, '#demo')
+}).mount('#demo')
 </script>
 
 <style>
index b32c96b16a9982a80ec0281fdf80db5669660a71..39fbc92080f5868b23a43892deb11735665b7644 100644 (file)
@@ -87,11 +87,11 @@ const DemoGrid = {
 </div>
 <!-- App script -->
 <script>
-const App = {
+Vue.createApp({
   components: {
     DemoGrid
   },
-  data: {
+  data: () => ({
     searchQuery: '',
     gridColumns: ['name', 'power'],
     gridData: [
@@ -100,10 +100,8 @@ const App = {
       { name: 'Jackie Chan', power: 7000 },
       { name: 'Jet Li', power: 8000 }
     ]
-  }
-}
-
-Vue.createApp().mount(App, '#demo')
+  })
+}).mount('#demo')
 </script>
 
 <style>
index afca4ef07ed356edc797746732432b2710ed781a..45b887827d80801fcaeee4337a6c529c06c8ab7a 100644 (file)
 <script>
 const delay = window.location.hash === '#test' ? 16 : 300
 
-const App = {
-  data: {
+Vue.createApp({
+  data: () => ({
     input: '# hello'
-  },
+  }),
   computed: {
     compiledMarkdown() {
       return marked(this.input, { sanitize: true })
@@ -24,9 +24,7 @@ const App = {
       this.input = e.target.value
     }, delay)
   }
-}
-
-Vue.createApp().mount(App, '#editor')
+}).mount('#editor')
 </script>
 
 <style>
index bf1115ce5579df26d8e9819e7cd2b68b053cce07..f2a1c19bff1bc86e868410a602625979620a63cd 100644 (file)
@@ -97,14 +97,15 @@ const globalStats = [
   { label: 'E', value: 100 },
   { label: 'F', value: 100 }
 ]
-const App = {
+
+Vue.createApp({
   components: {
     Polygraph
   },
-  data: {
+  data: () => ({
     newLabel: '',
     stats: globalStats
-  },
+  }),
   methods: {
     add(e) {
       e.preventDefault()
@@ -123,9 +124,7 @@ const App = {
       }
     }
   }
-}
-
-Vue.createApp().mount(App, '#demo')
+}).mount('#demo')
 </script>
 
 <style>
index adfe47e2618eb72ba93ce41dcbac4e4c07a2eea2..7a53a598f9201c1f2cc1af18b9635efdff4a9076 100644 (file)
@@ -82,14 +82,14 @@ const filters = {
   }
 }
 
-const App = {
+Vue.createApp({
   // app initial state
-  data: {
+  data: () => ({
     todos: todoStorage.fetch(),
     newTodo: '',
     editedTodo: null,
     visibility: 'all'
-  },
+  }),
 
   // watch todos change for localStorage persistence
   watch: {
@@ -192,7 +192,5 @@ const App = {
       }
     }
   }
-}
-
-Vue.createApp().mount(App, '#app')
+}).mount('#app')
 </script>
index 409d346eb44a800f8dfde8e9c2df147911f69a48..c447b76ca76457ab9bcf24051104b8e812d7a44e 100644 (file)
@@ -69,43 +69,43 @@ const TreeItem = {
 </ul>
 
 <script>
-const App = {
-  components: {
-    TreeItem
-  },
-  data: {
-    treeData: {
-      name: 'My Tree',
+const treeData = {
+  name: 'My Tree',
+  children: [
+    { name: 'hello' },
+    { name: 'wat' },
+    {
+      name: 'child folder',
       children: [
+        {
+          name: 'child folder',
+          children: [
+            { name: 'hello' },
+            { name: 'wat' }
+          ]
+        },
         { name: 'hello' },
         { name: 'wat' },
         {
           name: 'child folder',
           children: [
-            {
-              name: 'child folder',
-              children: [
-                { name: 'hello' },
-                { name: 'wat' }
-              ]
-            },
             { name: 'hello' },
-            { name: 'wat' },
-            {
-              name: 'child folder',
-              children: [
-                { name: 'hello' },
-                { name: 'wat' }
-              ]
-            }
+            { name: 'wat' }
           ]
         }
       ]
     }
-  }
+  ]
 }
 
-Vue.createApp().mount(App, '#demo')
+Vue.createApp({
+  components: {
+    TreeItem
+  },
+  data: () => ({
+    treeData
+  })
+}).mount('#demo')
 </script>
 
 <style>
index e2e4b1b23e308cc15f0b0d041b286bf9ea5a33ae..270662fe3865c4a74d4f4fdc42e2d1a035fba4e8 100644 (file)
@@ -32,7 +32,7 @@ const truncate = v => {
 
 const formatDate = v => v.replace(/T|Z/g, ' ')
 
-const App = {
+createApp({
   setup() {
     const currentBranch = ref('master')
     const commits = ref(null)
@@ -54,9 +54,7 @@ const App = {
       formatDate
     }
   }
-}
-
-createApp().mount(App, '#demo')
+}).mount('#demo')
 </script>
 
 <style>
index 3728bfd996b992e2d7413ae2c1f58ad807600b25..b2849fad3bc07e7babfd2cf78c165beea63f3df2 100644 (file)
@@ -93,11 +93,11 @@ const DemoGrid = {
 </div>
 <!-- App script -->
 <script>
-const App = {
+Vue.createApp({
   components: {
     DemoGrid
   },
-  data: {
+  data: () => ({
     searchQuery: '',
     gridColumns: ['name', 'power'],
     gridData: [
@@ -106,10 +106,8 @@ const App = {
       { name: 'Jackie Chan', power: 7000 },
       { name: 'Jet Li', power: 8000 }
     ]
-  }
-}
-
-Vue.createApp().mount(App, '#demo')
+  })
+}).mount('#demo')
 </script>
 
 <style>
index 1a29219023d3ab9f8d707878ea7cb2054e1f6b63..c851b42af81bcb0145344f94de9c1623738182d8 100644 (file)
@@ -11,7 +11,7 @@
 const delay = window.location.hash === '#test' ? 16 : 300
 const { ref, computed } = Vue
 
-const App = {
+Vue.createApp({
   setup() {
     const input = ref('# hello')
     const output = computed(() => marked(input.value, { sanitize: true }))
@@ -23,9 +23,7 @@ const App = {
       update
     }
   }
-}
-
-Vue.createApp().mount(App, '#editor')
+}).mount('#editor')
 </script>
 
 <style>
index f1538af180a8049e4fad562f5f925a9bd3f27992..4bdca965960ab3524f9ce8fcdc74fc27ac448ae5 100644 (file)
@@ -100,7 +100,8 @@ const globalStats = [
   { label: 'E', value: 100 },
   { label: 'F', value: 100 }
 ]
-const App = {
+
+createApp({
   components: {
     Polygraph
   },
@@ -133,9 +134,7 @@ const App = {
       remove
     }
   }
-}
-
-createApp().mount(App, '#demo')
+}).mount('#demo')
 </script>
 
 <style>
index 83a339d7f5f78e72b4772ca0ce4fb8cd82721f5f..791654e0581a0f99c1c050947a5f37a612f09046 100644 (file)
@@ -90,7 +90,7 @@ function pluralize (n) {
   return n === 1 ? 'item' : 'items'
 }
 
-const App = {
+createApp({
   setup () {
     const state = reactive({
       todos: todoStorage.fetch(),
@@ -202,7 +202,5 @@ const App = {
       }
     }
   }
-}
-
-createApp().mount(App, '#app')
+}).mount('#app')
 </script>
index ed16a79f04310f2e6cf31b29a5e6bc437ffb303c..a80a8ac964a07f0f20d9cde9ef7542ff7d579e6a 100644 (file)
@@ -72,43 +72,43 @@ const TreeItem = {
 </ul>
 
 <script>
-const App = {
-  components: {
-    TreeItem
-  },
-  data: {
-    treeData: {
-      name: 'My Tree',
+const treeData = {
+  name: 'My Tree',
+  children: [
+    { name: 'hello' },
+    { name: 'wat' },
+    {
+      name: 'child folder',
       children: [
+        {
+          name: 'child folder',
+          children: [
+            { name: 'hello' },
+            { name: 'wat' }
+          ]
+        },
         { name: 'hello' },
         { name: 'wat' },
         {
           name: 'child folder',
           children: [
-            {
-              name: 'child folder',
-              children: [
-                { name: 'hello' },
-                { name: 'wat' }
-              ]
-            },
             { name: 'hello' },
-            { name: 'wat' },
-            {
-              name: 'child folder',
-              children: [
-                { name: 'hello' },
-                { name: 'wat' }
-              ]
-            }
+            { name: 'wat' }
           ]
         }
       ]
     }
-  }
+  ]
 }
 
-Vue.createApp().mount(App, '#demo')
+Vue.createApp({
+  components: {
+    TreeItem
+  },
+  data: () => ({
+    treeData
+  })
+}).mount('#demo')
 </script>
 
 <style>
index 5535d6566cb39bdc94a4e6671612ada78bb42d63..13392e674b5c451dbcd82c1c2aa005ac6689f55c 100644 (file)
@@ -24,7 +24,7 @@ const Item = {
   template: `<div>{{ msg }} <button @click="$emit('rm')">x</button></div>`
 }
 
-const App = {
+Vue.createApp({
   components: {
     Item
   },
@@ -51,9 +51,7 @@ const App = {
       }
     }
   }
-}
-
-Vue.createApp().mount(App, '#app')
+}).mount('#app')
 </script>
 
 <style>
index ebbde2743aebedbc9822fd837660afd4ac2a79d3..3c8f1d071d03605f0e0c242e8834491b4e64954d 100644 (file)
@@ -56,13 +56,12 @@ const Modal = {
 </div>
 
 <script>
-const App = {
+Vue.createApp({
   components: { Modal },
-  data: {
+  data: () => ({
     showModal: false
-  }
-}
-Vue.createApp().mount(App, '#app')
+  })
+}).mount('#app')
 </script>
 
 <style>