Skip to content

Commit

Permalink
wip: more compat progress
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Apr 21, 2021
1 parent 62b8f4a commit 1b8f14e
Show file tree
Hide file tree
Showing 14 changed files with 270 additions and 53 deletions.
4 changes: 2 additions & 2 deletions packages/runtime-core/__tests__/componentSlots.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ describe('component: slots', () => {
expect(slots.default()).toMatchObject([normalizeVNode(h('span'))])
})

test('updateSlots: instance.slots should be update correctly (when slotType is number)', async () => {
test('updateSlots: instance.slots should be updated correctly (when slotType is number)', async () => {
const flag1 = ref(true)

let instance: any
Expand Down Expand Up @@ -124,7 +124,7 @@ describe('component: slots', () => {
expect(instance.slots).toHaveProperty('two')
})

test('updateSlots: instance.slots should be update correctly (when slotType is null)', async () => {
test('updateSlots: instance.slots should be updated correctly (when slotType is null)', async () => {
const flag1 = ref(true)

let instance: any
Expand Down
3 changes: 2 additions & 1 deletion packages/runtime-core/src/compat/compatConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,7 +262,8 @@ const deprecationData: Record<DeprecationTypes, DeprecationData> = {

[DeprecationTypes.PROPS_DEFAULT_THIS]: {
message: (key: string) =>
`props default value function no longer has access to "this". ` +
`props default value function no longer has access to "this". The compat ` +
`build only offers access to this.$options.` +
`(found in prop "${key}")`,
link: `https://v3.vuejs.org/guide/migration/props-default-this.html`
},
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime-core/src/compat/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ function convertLegacyFunctionalComponent(comp: ComponentOptions) {
data: instance.vnode.props || {},
scopedSlots: ctx.slots,
parent: instance.parent && instance.parent.proxy,
get slots() {
slots() {
return new Proxy(ctx.slots, legacySlotProxyHandlers)
},
get listeners() {
Expand Down
14 changes: 10 additions & 4 deletions packages/runtime-core/src/compat/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@ import { getCompatListeners } from './instanceListeners'
import { shallowReadonly } from '@vue/reactivity'
import { legacySlotProxyHandlers } from './component'
import { compatH } from './renderFn'
import { createCommentVNode, createTextVNode } from '../vnode'
import { renderList } from '../helpers/renderList'
import {
legacyBindObjectListeners,
legacyBindObjectProps,
legacyCheckKeyCodes,
legacyRenderSlot,
legacyRenderStatic
legacyRenderStatic,
legacyresolveScopedSlots
} from './renderHelpers'
import { createCommentVNode, createTextVNode } from '../vnode'
import { renderList } from '../helpers/renderList'

export function installCompatInstanceProperties(map: PublicPropertiesMap) {
const set = (target: any, key: any, val: any) => {
Expand Down Expand Up @@ -98,6 +101,9 @@ export function installCompatInstanceProperties(map: PublicPropertiesMap) {
_b: () => legacyBindObjectProps,
_e: () => createCommentVNode,
_v: () => createTextVNode,
_m: i => legacyRenderStatic.bind(null, i)
_m: i => legacyRenderStatic.bind(null, i),
_g: () => legacyBindObjectListeners,
_u: () => legacyresolveScopedSlots,
_k: i => legacyCheckKeyCodes.bind(null, i)
} as PublicPropertiesMap)
}
34 changes: 31 additions & 3 deletions packages/runtime-core/src/compat/props.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,39 @@
import { isArray } from '@vue/shared'
import { inject } from '../apiInject'
import { ComponentInternalInstance, Data } from '../component'
import { ComponentOptions, resolveMergedOptions } from '../componentOptions'
import { DeprecationTypes, warnDeprecation } from './compatConfig'

export function createPropsDefaultThis(propKey: string) {
export function createPropsDefaultThis(
instance: ComponentInternalInstance,
rawProps: Data,
propKey: string
) {
return new Proxy(
{},
{
get() {
warnDeprecation(DeprecationTypes.PROPS_DEFAULT_THIS, null, propKey)
get(_, key: string) {
__DEV__ &&
warnDeprecation(DeprecationTypes.PROPS_DEFAULT_THIS, null, propKey)
// $options
if (key === '$options') {
return resolveMergedOptions(instance)
}
// props
if (key in rawProps) {
return rawProps[key]
}
// injections
const injections = (instance.type as ComponentOptions).inject
if (injections) {
if (isArray(injections)) {
if (injections.includes(key)) {
return inject(key)
}
} else if (key in injections) {
return inject(key)
}
}
}
}
)
Expand Down
92 changes: 78 additions & 14 deletions packages/runtime-core/src/compat/renderFn.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {
extend,
hyphenate,
isArray,
isObject,
makeMap,
normalizeClass,
normalizeStyle,
ShapeFlags,
Expand All @@ -14,6 +16,7 @@ import {
Data,
InternalRenderFunction
} from '../component'
import { currentRenderingInstance } from '../componentRenderContext'
import { DirectiveArguments, withDirectives } from '../directives'
import {
resolveDirective,
Expand All @@ -27,7 +30,12 @@ import {
VNodeArrayChildren,
VNodeProps
} from '../vnode'
import { checkCompatEnabled, DeprecationTypes } from './compatConfig'
import {
checkCompatEnabled,
DeprecationTypes,
isCompatEnabled
} from './compatConfig'
import { compatModelEventPrefix } from './vModel'

const v3CompiledRenderFnRE = /^(?:function \w+)?\(_ctx, _cache/

Expand Down Expand Up @@ -76,6 +84,11 @@ interface LegacyVNodeProps {
props?: Record<string, unknown>
slot?: string
scopedSlots?: Record<string, Function>
model?: {
value: any
callback: (v: any) => void
expression: string
}
}

interface LegacyVNodeDirective {
Expand Down Expand Up @@ -107,20 +120,30 @@ export function compatH(
propsOrChildren?: any,
children?: any
): VNode {
// to support v2 string component name lookup
type = resolveDynamicComponent(type)
// to support v2 string component name look!up
if (typeof type === 'string') {
const t = hyphenate(type)
if (t === 'transition' || t === 'transition-group' || t === 'keep-alive') {
// since transition and transition-group are runtime-dom-specific,
// we cannot import them directly here. Instead they are registered using
// special keys in @vue/compat entry.
type = `__compat__${t}`
}
type = resolveDynamicComponent(type)
}

const l = arguments.length
if (l === 2) {
if (isObject(propsOrChildren) && !isArray(propsOrChildren)) {
const is2ndArgArrayChildren = isArray(propsOrChildren)
if (l === 2 || is2ndArgArrayChildren) {
if (isObject(propsOrChildren) && !is2ndArgArrayChildren) {
// single vnode without props
if (isVNode(propsOrChildren)) {
return convertLegacySlots(createVNode(type, null, [propsOrChildren]))
}
// props without children
return convertLegacySlots(
convertLegacyDirectives(
createVNode(type, convertLegacyProps(propsOrChildren)),
createVNode(type, convertLegacyProps(propsOrChildren, type)),
propsOrChildren
)
)
Expand All @@ -134,15 +157,20 @@ export function compatH(
}
return convertLegacySlots(
convertLegacyDirectives(
createVNode(type, convertLegacyProps(propsOrChildren), children),
createVNode(type, convertLegacyProps(propsOrChildren, type), children),
propsOrChildren
)
)
}
}

const skipLegacyRootLevelProps = /*#__PURE__*/ makeMap(
'refInFor,staticStyle,staticClass,directives,model'
)

function convertLegacyProps(
legacyProps?: LegacyVNodeProps
legacyProps: LegacyVNodeProps | undefined,
type: any
): Data & VNodeProps | null {
if (!legacyProps) {
return null
Expand Down Expand Up @@ -172,11 +200,7 @@ function convertLegacyProps(
}
}
}
} else if (
key !== 'refInFor' &&
key !== 'staticStyle' &&
key !== 'staticClass'
) {
} else if (!skipLegacyRootLevelProps(key)) {
converted[key] = legacyProps[key as keyof LegacyVNodeProps]
}
}
Expand All @@ -188,6 +212,13 @@ function convertLegacyProps(
converted.style = normalizeStyle([legacyProps.staticStyle, converted.style])
}

if (legacyProps.model && isObject(type)) {
// v2 compiled component v-model
const { prop = 'value', event = 'input' } = (type as any).model || {}
converted[prop] = legacyProps.model.value
converted[compatModelEventPrefix + event] = legacyProps.model.callback
}

return converted
}

Expand Down Expand Up @@ -237,7 +268,12 @@ function convertLegacySlots(vnode: VNode): VNode {
const child = children[i]
const slotName =
(isVNode(child) && child.props && child.props.slot) || 'default'
;(slots[slotName] || (slots[slotName] = [] as any[])).push(child)
const slot = slots[slotName] || (slots[slotName] = [] as any[])
if (isVNode(child) && child.type === 'template') {
slot.push(child.children)
} else {
slot.push(child)
}
}
if (slots) {
for (const key in slots) {
Expand All @@ -263,3 +299,31 @@ function convertLegacySlots(vnode: VNode): VNode {

return vnode
}

export function defineLegacyVNodeProperties(vnode: VNode) {
if (
isCompatEnabled(DeprecationTypes.RENDER_FUNCTION, currentRenderingInstance)
) {
const getInstance = () => vnode.component && vnode.component.proxy
let componentOptions: any
Object.defineProperties(vnode, {
elm: { get: () => vnode.el },
componentInstance: { get: getInstance },
child: { get: getInstance },
componentOptions: {
get: () => {
if (vnode.shapeFlag & ShapeFlags.STATEFUL_COMPONENT) {
if (componentOptions) {
return componentOptions
}
return (componentOptions = {
Ctor: vnode.type,
propsData: vnode.props,
children: vnode.children
})
}
}
}
})
}
}
Loading

0 comments on commit 1b8f14e

Please sign in to comment.