From 960e9deaeda6e659531c9635cb3aa1ea1c7942e4 Mon Sep 17 00:00:00 2001 From: Evan You Date: Thu, 8 Apr 2021 10:06:12 -0400 Subject: [PATCH] wip: vm.$listeners compat --- .../runtime-core/src/compat/deprecations.ts | 9 ++ packages/runtime-core/src/compat/instance.ts | 8 +- .../{children.ts => instanceChildren.ts} | 2 +- ...ventEmitter.ts => instanceEventEmitter.ts} | 0 .../src/compat/instanceListeners.ts | 20 ++++ packages/runtime-core/src/compat/renderFn.ts | 99 +++++++++++++++++++ packages/runtime-core/src/componentEmits.ts | 2 +- packages/vue-compat/package.json | 4 +- packages/vue/package.json | 2 +- rollup.config.js | 4 +- 10 files changed, 140 insertions(+), 10 deletions(-) rename packages/runtime-core/src/compat/{children.ts => instanceChildren.ts} (96%) rename packages/runtime-core/src/compat/{eventEmitter.ts => instanceEventEmitter.ts} (100%) create mode 100644 packages/runtime-core/src/compat/instanceListeners.ts create mode 100644 packages/runtime-core/src/compat/renderFn.ts diff --git a/packages/runtime-core/src/compat/deprecations.ts b/packages/runtime-core/src/compat/deprecations.ts index 7173cbdc..516cd557 100644 --- a/packages/runtime-core/src/compat/deprecations.ts +++ b/packages/runtime-core/src/compat/deprecations.ts @@ -23,6 +23,7 @@ export const enum DeprecationTypes { INSTANCE_EVENT_EMITTER = 'INSTANCE_EVENT_EMITTER', INSTANCE_EVENT_HOOKS = 'INSTANCE_EVENT_HOOKS', INSTANCE_CHILDREN = 'INSTANCE_CHILDREN', + INSTANCE_LISTENERS = 'INSTANCE_LISTENERS', OPTIONS_DATA_FN = 'OPTIONS_DATA_FN', OPTIONS_DATA_MERGE = 'OPTIONS_DATA_MERGE', @@ -173,6 +174,14 @@ const deprecationData: Record = { link: `https://v3.vuejs.org/guide/migration/children.html` }, + [DeprecationTypes.INSTANCE_LISTENERS]: { + message: + `vm.$listeners has been removed. Parent v-on listeners are now ` + + `included in vm.$attrs and it is no longer necessary to separately use ` + + `v-on="$listeners" if you are already using v-bind="$attrs".`, + link: `https://v3.vuejs.org/guide/migration/listeners-removed.html` + }, + [DeprecationTypes.OPTIONS_DATA_FN]: { message: `The "data" option can no longer be a plain object. ` + diff --git a/packages/runtime-core/src/compat/instance.ts b/packages/runtime-core/src/compat/instance.ts index ec070a18..cbb4774f 100644 --- a/packages/runtime-core/src/compat/instance.ts +++ b/packages/runtime-core/src/compat/instance.ts @@ -1,9 +1,10 @@ import { extend, NOOP } from '@vue/shared' import { PublicPropertiesMap } from '../componentPublicInstance' -import { getInstanceChildren } from './children' +import { getCompatChildren } from './instanceChildren' import { assertCompatEnabled } from './compatConfig' import { DeprecationTypes } from './deprecations' -import { off, on, once } from './eventEmitter' +import { off, on, once } from './instanceEventEmitter' +import { getCompatListeners } from './instanceListeners' export function installCompatInstanceProperties(map: PublicPropertiesMap) { const set = (target: any, key: any, val: any) => { @@ -36,6 +37,7 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) { $on: i => on.bind(null, i), $once: i => once.bind(null, i), $off: i => off.bind(null, i), - $children: getInstanceChildren + $children: getCompatChildren, + $listeners: getCompatListeners } as PublicPropertiesMap) } diff --git a/packages/runtime-core/src/compat/children.ts b/packages/runtime-core/src/compat/instanceChildren.ts similarity index 96% rename from packages/runtime-core/src/compat/children.ts rename to packages/runtime-core/src/compat/instanceChildren.ts index b0b6a6be..4bdaadb5 100644 --- a/packages/runtime-core/src/compat/children.ts +++ b/packages/runtime-core/src/compat/instanceChildren.ts @@ -5,7 +5,7 @@ import { VNode } from '../vnode' import { assertCompatEnabled } from './compatConfig' import { DeprecationTypes } from './deprecations' -export function getInstanceChildren( +export function getCompatChildren( instance: ComponentInternalInstance ): ComponentPublicInstance[] { assertCompatEnabled(DeprecationTypes.INSTANCE_CHILDREN) diff --git a/packages/runtime-core/src/compat/eventEmitter.ts b/packages/runtime-core/src/compat/instanceEventEmitter.ts similarity index 100% rename from packages/runtime-core/src/compat/eventEmitter.ts rename to packages/runtime-core/src/compat/instanceEventEmitter.ts diff --git a/packages/runtime-core/src/compat/instanceListeners.ts b/packages/runtime-core/src/compat/instanceListeners.ts new file mode 100644 index 00000000..640bbfcf --- /dev/null +++ b/packages/runtime-core/src/compat/instanceListeners.ts @@ -0,0 +1,20 @@ +import { isOn } from '@vue/shared' +import { ComponentInternalInstance } from '../component' +import { assertCompatEnabled } from './compatConfig' +import { DeprecationTypes } from './deprecations' + +export function getCompatListeners(instance: ComponentInternalInstance) { + assertCompatEnabled(DeprecationTypes.INSTANCE_LISTENERS) + + const listeners: Record = {} + const rawProps = instance.vnode.props + if (!rawProps) { + return listeners + } + for (const key in rawProps) { + if (isOn(key)) { + listeners[key[2].toLowerCase() + key.slice(3)] = rawProps[key] + } + } + return listeners +} diff --git a/packages/runtime-core/src/compat/renderFn.ts b/packages/runtime-core/src/compat/renderFn.ts new file mode 100644 index 00000000..b9074af1 --- /dev/null +++ b/packages/runtime-core/src/compat/renderFn.ts @@ -0,0 +1,99 @@ +import { isArray, isObject } from '@vue/shared' +import { Component, Data } from '../component' +import { + createVNode, + isVNode, + VNode, + VNodeArrayChildren, + VNodeProps +} from '../vnode' + +interface LegacyVNodeProps { + key?: string | number + ref?: string + refInFor?: boolean + + staticClass?: string + class?: unknown + staticStyle?: Record + style?: Record + attrs?: Record + domProps?: Record + on?: Record + nativeOn?: Record + directives?: LegacyVNodeDirective[] + + slot?: string + scopedSlots?: Record +} + +interface LegacyVNodeDirective { + name: string + value: unknown + arg?: string + modifiers?: Record +} + +type LegacyVNodeChildren = + | string + | number + | boolean + | VNode + | VNodeArrayChildren + +export function h( + type: string | Component, + children?: LegacyVNodeChildren +): VNode +export function h( + type: string | Component, + props?: LegacyVNodeProps, + children?: LegacyVNodeChildren +): VNode + +export function h(type: any, propsOrChildren?: any, children?: any): VNode { + const l = arguments.length + if (l === 2) { + if (isObject(propsOrChildren) && !isArray(propsOrChildren)) { + // single vnode without props + if (isVNode(propsOrChildren)) { + return convertLegacySlots(createVNode(type, null, [propsOrChildren])) + } + // props without children + return convertLegacyDirectives( + createVNode(type, convertLegacyProps(propsOrChildren)), + propsOrChildren + ) + } else { + // omit props + return convertLegacySlots(createVNode(type, null, propsOrChildren)) + } + } else { + if (l > 3) { + children = Array.prototype.slice.call(arguments, 2) + } else if (l === 3 && isVNode(children)) { + children = [children] + } + return convertLegacySlots( + convertLegacyDirectives( + createVNode(type, convertLegacyProps(propsOrChildren), children), + propsOrChildren + ) + ) + } +} + +function convertLegacyProps(props: LegacyVNodeProps): Data & VNodeProps { + // TODO + return {} +} + +function convertLegacyDirectives(vnode: VNode, props: LegacyVNodeProps): VNode { + // TODO + return vnode +} + +function convertLegacySlots(vnode: VNode): VNode { + // TODO + return vnode +} diff --git a/packages/runtime-core/src/componentEmits.ts b/packages/runtime-core/src/componentEmits.ts index f40e67ab..73cd2b70 100644 --- a/packages/runtime-core/src/componentEmits.ts +++ b/packages/runtime-core/src/componentEmits.ts @@ -21,7 +21,7 @@ import { warn } from './warning' import { UnionToIntersection } from './helpers/typeUtils' import { devtoolsComponentEmit } from './devtools' import { AppContext } from './apiCreateApp' -import { emit as compatEmit } from './compat/eventEmitter' +import { emit as compatEmit } from './compat/instanceEventEmitter' export type ObjectEmitsOptions = Record< string, diff --git a/packages/vue-compat/package.json b/packages/vue-compat/package.json index 60647569..205b3fec 100644 --- a/packages/vue-compat/package.json +++ b/packages/vue-compat/package.json @@ -1,9 +1,9 @@ { "name": "@vue/compat", "version": "3.0.11", - "description": "@vue/compat", + "description": "Vue 3 compatibility build for Vue 2", "main": "index.js", - "module": "dist/vue.esm-bundler.js", + "module": "dist/vue.runtime.esm-bundler.js", "types": "dist/vue.d.ts", "unpkg": "dist/vue.global.js", "jsdelivr": "dist/vue.global.js", diff --git a/packages/vue/package.json b/packages/vue/package.json index 991561d5..7898508a 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,7 +1,7 @@ { "name": "vue", "version": "3.0.11", - "description": "vue", + "description": "The progressive JavaScript framework for buiding modern web UI.", "main": "index.js", "module": "dist/vue.runtime.esm-bundler.js", "types": "dist/vue.d.ts", diff --git a/rollup.config.js b/rollup.config.js index eced8ac8..844d912e 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -120,13 +120,13 @@ function createConfig(format, output, plugins = []) { let external = [] - if (isGlobalBuild || isBrowserESMBuild) { + if (isGlobalBuild || isBrowserESMBuild || isCompatBuild) { if (!packageOptions.enableNonBrowserBranches) { // normal browser builds - non-browser only imports are tree-shaken, // they are only listed here to suppress warnings. external = ['source-map', '@babel/parser', 'estree-walker'] } - } else if (!isCompatBuild) { + } else { // Node / esm-bundler builds. // externalize all deps unless it's the compat build. external = [