wip: vm.$listeners compat

This commit is contained in:
Evan You 2021-04-08 10:06:12 -04:00
parent c1e5cfe7d6
commit 960e9deaed
10 changed files with 140 additions and 10 deletions

@ -23,6 +23,7 @@ export const enum DeprecationTypes {
INSTANCE_EVENT_EMITTER = 'INSTANCE_EVENT_EMITTER', INSTANCE_EVENT_EMITTER = 'INSTANCE_EVENT_EMITTER',
INSTANCE_EVENT_HOOKS = 'INSTANCE_EVENT_HOOKS', INSTANCE_EVENT_HOOKS = 'INSTANCE_EVENT_HOOKS',
INSTANCE_CHILDREN = 'INSTANCE_CHILDREN', INSTANCE_CHILDREN = 'INSTANCE_CHILDREN',
INSTANCE_LISTENERS = 'INSTANCE_LISTENERS',
OPTIONS_DATA_FN = 'OPTIONS_DATA_FN', OPTIONS_DATA_FN = 'OPTIONS_DATA_FN',
OPTIONS_DATA_MERGE = 'OPTIONS_DATA_MERGE', OPTIONS_DATA_MERGE = 'OPTIONS_DATA_MERGE',
@ -173,6 +174,14 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {
link: `https://v3.vuejs.org/guide/migration/children.html` 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]: { [DeprecationTypes.OPTIONS_DATA_FN]: {
message: message:
`The "data" option can no longer be a plain object. ` + `The "data" option can no longer be a plain object. ` +

@ -1,9 +1,10 @@
import { extend, NOOP } from '@vue/shared' import { extend, NOOP } from '@vue/shared'
import { PublicPropertiesMap } from '../componentPublicInstance' import { PublicPropertiesMap } from '../componentPublicInstance'
import { getInstanceChildren } from './children' import { getCompatChildren } from './instanceChildren'
import { assertCompatEnabled } from './compatConfig' import { assertCompatEnabled } from './compatConfig'
import { DeprecationTypes } from './deprecations' 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) { export function installCompatInstanceProperties(map: PublicPropertiesMap) {
const set = (target: any, key: any, val: any) => { const set = (target: any, key: any, val: any) => {
@ -36,6 +37,7 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
$on: i => on.bind(null, i), $on: i => on.bind(null, i),
$once: i => once.bind(null, i), $once: i => once.bind(null, i),
$off: i => off.bind(null, i), $off: i => off.bind(null, i),
$children: getInstanceChildren $children: getCompatChildren,
$listeners: getCompatListeners
} as PublicPropertiesMap) } as PublicPropertiesMap)
} }

@ -5,7 +5,7 @@ import { VNode } from '../vnode'
import { assertCompatEnabled } from './compatConfig' import { assertCompatEnabled } from './compatConfig'
import { DeprecationTypes } from './deprecations' import { DeprecationTypes } from './deprecations'
export function getInstanceChildren( export function getCompatChildren(
instance: ComponentInternalInstance instance: ComponentInternalInstance
): ComponentPublicInstance[] { ): ComponentPublicInstance[] {
assertCompatEnabled(DeprecationTypes.INSTANCE_CHILDREN) assertCompatEnabled(DeprecationTypes.INSTANCE_CHILDREN)

@ -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<string, Function | Function[]> = {}
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
}

@ -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<string, unknown>
style?: Record<string, unknown>
attrs?: Record<string, unknown>
domProps?: Record<string, unknown>
on?: Record<string, Function | Function[]>
nativeOn?: Record<string, Function | Function[]>
directives?: LegacyVNodeDirective[]
slot?: string
scopedSlots?: Record<string, Function>
}
interface LegacyVNodeDirective {
name: string
value: unknown
arg?: string
modifiers?: Record<string, boolean>
}
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
}

@ -21,7 +21,7 @@ import { warn } from './warning'
import { UnionToIntersection } from './helpers/typeUtils' import { UnionToIntersection } from './helpers/typeUtils'
import { devtoolsComponentEmit } from './devtools' import { devtoolsComponentEmit } from './devtools'
import { AppContext } from './apiCreateApp' import { AppContext } from './apiCreateApp'
import { emit as compatEmit } from './compat/eventEmitter' import { emit as compatEmit } from './compat/instanceEventEmitter'
export type ObjectEmitsOptions = Record< export type ObjectEmitsOptions = Record<
string, string,

@ -1,9 +1,9 @@
{ {
"name": "@vue/compat", "name": "@vue/compat",
"version": "3.0.11", "version": "3.0.11",
"description": "@vue/compat", "description": "Vue 3 compatibility build for Vue 2",
"main": "index.js", "main": "index.js",
"module": "dist/vue.esm-bundler.js", "module": "dist/vue.runtime.esm-bundler.js",
"types": "dist/vue.d.ts", "types": "dist/vue.d.ts",
"unpkg": "dist/vue.global.js", "unpkg": "dist/vue.global.js",
"jsdelivr": "dist/vue.global.js", "jsdelivr": "dist/vue.global.js",

@ -1,7 +1,7 @@
{ {
"name": "vue", "name": "vue",
"version": "3.0.11", "version": "3.0.11",
"description": "vue", "description": "The progressive JavaScript framework for buiding modern web UI.",
"main": "index.js", "main": "index.js",
"module": "dist/vue.runtime.esm-bundler.js", "module": "dist/vue.runtime.esm-bundler.js",
"types": "dist/vue.d.ts", "types": "dist/vue.d.ts",

@ -120,13 +120,13 @@ function createConfig(format, output, plugins = []) {
let external = [] let external = []
if (isGlobalBuild || isBrowserESMBuild) { if (isGlobalBuild || isBrowserESMBuild || isCompatBuild) {
if (!packageOptions.enableNonBrowserBranches) { if (!packageOptions.enableNonBrowserBranches) {
// normal browser builds - non-browser only imports are tree-shaken, // normal browser builds - non-browser only imports are tree-shaken,
// they are only listed here to suppress warnings. // they are only listed here to suppress warnings.
external = ['source-map', '@babel/parser', 'estree-walker'] external = ['source-map', '@babel/parser', 'estree-walker']
} }
} else if (!isCompatBuild) { } else {
// Node / esm-bundler builds. // Node / esm-bundler builds.
// externalize all deps unless it's the compat build. // externalize all deps unless it's the compat build.
external = [ external = [