From c07751fd3605f301dc0f02fd2a48acc7ba7a0397 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 23 Jan 2020 15:05:38 -0500 Subject: [PATCH] refactor: adjust `createApp` related API signatures 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() ``` --- .../{apiApp.spec.ts => apiCreateApp.spec.ts} | 215 ++++++++---------- .../__tests__/componentProxy.spec.ts | 20 +- .../__tests__/helpers/resolveAssets.spec.ts | 13 +- packages/runtime-core/src/apiCreateApp.ts | 44 ++-- packages/runtime-core/src/index.ts | 8 +- packages/runtime-core/src/renderer.ts | 4 +- .../__tests__/directives/vModel.spec.ts | 27 ++- .../__tests__/directives/vShow.spec.ts | 15 +- packages/runtime-dom/src/index.ts | 27 +-- packages/runtime-test/src/index.ts | 4 +- packages/vue/__tests__/index.spec.ts | 28 ++- packages/vue/examples/classic/commits.html | 10 +- packages/vue/examples/classic/grid.html | 10 +- packages/vue/examples/classic/markdown.html | 10 +- packages/vue/examples/classic/svg.html | 11 +- packages/vue/examples/classic/todomvc.html | 10 +- packages/vue/examples/classic/tree.html | 48 ++-- .../vue/examples/composition/commits.html | 6 +- packages/vue/examples/composition/grid.html | 10 +- .../vue/examples/composition/markdown.html | 6 +- packages/vue/examples/composition/svg.html | 7 +- .../vue/examples/composition/todomvc.html | 6 +- packages/vue/examples/composition/tree.html | 48 ++-- packages/vue/examples/transition/list.html | 6 +- packages/vue/examples/transition/modal.html | 9 +- 25 files changed, 276 insertions(+), 326 deletions(-) rename packages/runtime-core/__tests__/{apiApp.spec.ts => apiCreateApp.spec.ts} (81%) diff --git a/packages/runtime-core/__tests__/apiApp.spec.ts b/packages/runtime-core/__tests__/apiCreateApp.spec.ts similarity index 81% rename from packages/runtime-core/__tests__/apiApp.spec.ts rename to packages/runtime-core/__tests__/apiCreateApp.spec.ts index 6fb8239b8f9..0442cf70626 100644 --- a/packages/runtime-core/__tests__/apiApp.spec.ts +++ b/packages/runtime-core/__tests__/apiCreateApp.spec.ts @@ -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(`
foobar!barbaz-local!
`) }) 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() diff --git a/packages/runtime-core/__tests__/componentProxy.spec.ts b/packages/runtime-core/__tests__/componentProxy.spec.ts index ddfd8cab0bf..0790f2246e1 100644 --- a/packages/runtime-core/__tests__/componentProxy.spec.ts +++ b/packages/runtime-core/__tests__/componentProxy.spec.ts @@ -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) diff --git a/packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts b/packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts index 392311c1cb5..779814b7930 100644 --- a/packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts +++ b/packages/runtime-core/__tests__/helpers/resolveAssets.spec.ts @@ -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) diff --git a/packages/runtime-core/src/apiCreateApp.ts b/packages/runtime-core/src/apiCreateApp.ts index fdd377d0264..a01b5ecb608 100644 --- a/packages/runtime-core/src/apiCreateApp.ts +++ b/packages/runtime-core/src/apiCreateApp.ts @@ -16,16 +16,11 @@ export interface App { 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 }, - rootContainer: HostElement | string, - rootProps?: Data - ): ComponentPublicInstance + mount(rootContainer: HostElement | string): ComponentPublicInstance unmount(rootContainer: HostElement | string): void provide(key: InjectionKey | string, value: T): this + rootComponent: Component + rootContainer: HostElement | null } export interface AppConfig { @@ -79,16 +74,30 @@ export function createAppContext(): AppContext { } } +export type CreateAppFunction = ( + rootComponent: + | Component + // for compatibility with defineComponent() return types + | { new (): ComponentPublicInstance }, + rootProps?: Data | null +) => App + export function createAppAPI( render: RootRenderFunction -): () => App { - return function createApp(): App { +): CreateAppFunction { + 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( 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( render(vnode, rootContainer) isMounted = true + app.rootContainer = rootContainer return vnode.component!.proxy } else if (__DEV__) { warn( @@ -198,8 +204,12 @@ export function createAppAPI( } }, - 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) { diff --git a/packages/runtime-core/src/index.ts b/packages/runtime-core/src/index.ts index 181e53f8dd2..435ede78176 100644 --- a/packages/runtime-core/src/index.ts +++ b/packages/runtime-core/src/index.ts @@ -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, diff --git a/packages/runtime-core/src/renderer.ts b/packages/runtime-core/src/renderer.ts index d26f73dae9a..7af49a21d93 100644 --- a/packages/runtime-core/src/renderer.ts +++ b/packages/runtime-core/src/renderer.ts @@ -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 ): { render: RootRenderFunction - createApp: () => App + createApp: CreateAppFunction } { type HostVNode = VNode type HostVNodeChildren = VNodeChildren diff --git a/packages/runtime-dom/__tests__/directives/vModel.spec.ts b/packages/runtime-dom/__tests__/directives/vModel.spec.ts index cd187ff80af..aac67c00d2d 100644 --- a/packages/runtime-dom/__tests__/directives/vModel.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vModel.spec.ts @@ -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]') diff --git a/packages/runtime-dom/__tests__/directives/vShow.spec.ts b/packages/runtime-dom/__tests__/directives/vShow.spec.ts index 76eef6513e4..6c21e5f83f0 100644 --- a/packages/runtime-dom/__tests__/directives/vShow.spec.ts +++ b/packages/runtime-dom/__tests__/directives/vShow.spec.ts @@ -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 diff --git a/packages/runtime-dom/src/index.ts b/packages/runtime-dom/src/index.ts index 8d5de566483..51a8e0aa53d 100644 --- a/packages/runtime-dom/src/index.ts +++ b/packages/runtime-dom/src/index.ts @@ -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 -export const createApp = (): App => { - const app = baseCreateApp() +export const createApp: CreateAppFunction = (...args) => { + const app = baseCreateApp(...args) if (__DEV__) { // Inject `isNativeTag` @@ -29,8 +29,8 @@ export const createApp = (): App => { }) } - 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 => { return } } + const component = app.rootComponent if ( __RUNTIME_COMPILE__ && !isFunction(component) && @@ -49,19 +50,7 @@ export const createApp = (): App => { } // 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 diff --git a/packages/runtime-test/src/index.ts b/packages/runtime-test/src/index.ts index c057da7e018..7b6dcfd97e2 100644 --- a/packages/runtime-test/src/index.ts +++ b/packages/runtime-test/src/index.ts @@ -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 -export const createApp = baseCreateApp as () => App +export const createApp = baseCreateApp as CreateAppFunction // convenience for one-off render validations export function renderToString(vnode: VNode) { diff --git a/packages/vue/__tests__/index.spec.ts b/packages/vue/__tests__/index.spec.ts index 4a7a06bb64d..3bde76341e8 100644 --- a/packages/vue/__tests__/index.spec.ts +++ b/packages/vue/__tests__/index.spec.ts @@ -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: `
` } - 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: '' - } + }) + const container = document.createElement('div') app.config.isCustomElement = tag => tag === 'custom' - app.mount(App, container) + app.mount(container) expect(container.innerHTML).toBe('') }) 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') }) }) diff --git a/packages/vue/examples/classic/commits.html b/packages/vue/examples/classic/commits.html index d88f0e28b25..1a258753874 100644 --- a/packages/vue/examples/classic/commits.html +++ b/packages/vue/examples/classic/commits.html @@ -24,12 +24,12 @@

Latest Vue.js Commits