From b3208a5941acdf932b6e70eebe3ea42cbb12d4f5 Mon Sep 17 00:00:00 2001 From: Evan You Date: Wed, 19 Sep 2018 23:19:25 -0400 Subject: [PATCH] wip: root Vue compat --- packages/core/src/componentUtils.ts | 10 ++++++- packages/core/src/createRenderer.ts | 10 +++---- packages/core/src/index.ts | 5 +++- packages/vue/src/index.ts | 45 ++++++++++++++++++----------- 4 files changed, 46 insertions(+), 24 deletions(-) diff --git a/packages/core/src/componentUtils.ts b/packages/core/src/componentUtils.ts index fe0e43af..6ef7c27c 100644 --- a/packages/core/src/componentUtils.ts +++ b/packages/core/src/componentUtils.ts @@ -1,5 +1,6 @@ import { VNodeFlags } from './flags' import { EMPTY_OBJ } from './utils' +import { h } from './h' import { VNode, createFragment } from './vdom' import { Component, MountedComponent, ComponentClass } from './component' import { createTextVNode, cloneVNode } from './vdom' @@ -153,6 +154,7 @@ export function shouldUpdateFunctionalComponent( return shouldUpdate } +// compat only export function createComponentClassFromOptions( options: ComponentOptions ): ComponentClass { @@ -165,7 +167,13 @@ export function createComponentClassFromOptions( for (const key in options) { const value = options[key] if (typeof value === 'function') { - ;(ObjectComponent.prototype as any)[key] = value + ;(ObjectComponent.prototype as any)[key] = + key === 'render' + ? // normalize render for legacy signature + function render() { + return value.call(this, h) + } + : value } if (key === 'computed') { const isGet = typeof value === 'function' diff --git a/packages/core/src/createRenderer.ts b/packages/core/src/createRenderer.ts index 7d5ccd63..0541d1fb 100644 --- a/packages/core/src/createRenderer.ts +++ b/packages/core/src/createRenderer.ts @@ -1174,11 +1174,11 @@ export function createRenderer(options: RendererOptions) { isSVG: boolean, endNode: RenderNode | RenderFragment | null ): RenderNode { - const instance = createComponentInstance( - parentVNode, - Component, - parentComponent - ) + // a vnode may already have an instance if this is a compat call + // with new Vue() + const instance = + (__COMPAT__ && (parentVNode.children as MountedComponent)) || + createComponentInstance(parentVNode, Component, parentComponent) const queueUpdate = (instance.$forceUpdate = () => { queueJob(instance._updateHandle, flushHooks) diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 14fa9679..6cd5decc 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -10,8 +10,11 @@ export const Component = InternalComponent as ComponentClass // observer api export * from '@vue/observer' +// internal api +export { createComponentInstance } from './componentUtils' + // flags & types -export { FunctionalComponent } from './component' +export { ComponentClass, FunctionalComponent } from './component' export { ComponentOptions, PropType } from './componentOptions' export { VNodeFlags, ChildrenFlags } from './flags' export { VNode, VNodeData, VNodeChildren, Key, Ref, Slots, Slot } from './vdom' diff --git a/packages/vue/src/index.ts b/packages/vue/src/index.ts index d98bad21..a29912cb 100644 --- a/packages/vue/src/index.ts +++ b/packages/vue/src/index.ts @@ -1,25 +1,36 @@ -import { h, render, ComponentOptions } from '@vue/renderer-dom' +import { + h, + render, + Component, + ComponentOptions, + createComponentInstance +} from '@vue/renderer-dom' -function Vue(options: ComponentOptions & { el: any }) { - const { el, render: r } = options +class Vue extends Component { + static h = h + static render = render - if (r) { - options.render = function(props, slots) { - return r.call(this, h, props, slots) + constructor(options: ComponentOptions & { el: any }) { + super() + if (!options) { + return } - } - function mount(el: any) { - const dom = document.querySelector(el) - render(h(options), dom) - return (dom as any).vnode.children.$proxy - } + const vnode = h(options) + const instance = createComponentInstance(vnode, options._normalized, null) + vnode.children = instance - if (el) { - return mount(el) - } else { - return { - $mount: mount + function mount(el: any) { + const dom = document.querySelector(el) + render(vnode, dom) + return instance.$proxy + } + + if (options.el) { + return mount(options.el) + } else { + ;(instance as any).$mount = mount + return instance.$proxy } } }