feat(transition): properly handle transition & transition-group in compiler
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { NO, makeMap, isArray } from '@vue/shared'
|
||||
import { NO, isArray } from '@vue/shared'
|
||||
import {
|
||||
ErrorCodes,
|
||||
createCompilerError,
|
||||
@@ -8,7 +8,8 @@ import {
|
||||
import {
|
||||
assert,
|
||||
advancePositionWithMutation,
|
||||
advancePositionWithClone
|
||||
advancePositionWithClone,
|
||||
isCoreComponent
|
||||
} from './utils'
|
||||
import {
|
||||
Namespace,
|
||||
@@ -29,22 +30,12 @@ import {
|
||||
} from './ast'
|
||||
import { extend } from '@vue/shared'
|
||||
|
||||
// Portal and Fragment are native types, not components
|
||||
const isBuiltInComponent = /*#__PURE__*/ makeMap(
|
||||
`suspense,keep-alive,base-transition`,
|
||||
true
|
||||
)
|
||||
|
||||
export interface ParserOptions {
|
||||
isVoidTag?: (tag: string) => boolean // e.g. img, br, hr
|
||||
isNativeTag?: (tag: string) => boolean // e.g. loading-indicator in weex
|
||||
isPreTag?: (tag: string) => boolean // e.g. <pre> where whitespace is intact
|
||||
isCustomElement?: (tag: string) => boolean
|
||||
// for importing platform-specific components from the runtime.
|
||||
// e.g. <transition> for runtime-dom
|
||||
// However this is only needed if isNativeTag is not specified, since when
|
||||
// isNativeTag is specified anything that is not native is a component.
|
||||
isBuiltInComponent?: (tag: string) => boolean
|
||||
isBuiltInComponent?: (tag: string) => symbol | void
|
||||
getNamespace?: (tag: string, parent: ElementNode | undefined) => Namespace
|
||||
getTextMode?: (tag: string, ns: Namespace) => TextModes
|
||||
delimiters?: [string, string] // ['{{', '}}']
|
||||
@@ -483,7 +474,7 @@ function parseTag(
|
||||
if (options.isNativeTag) {
|
||||
if (!options.isNativeTag(tag)) tagType = ElementTypes.COMPONENT
|
||||
} else if (
|
||||
isBuiltInComponent(tag) ||
|
||||
isCoreComponent(tag) ||
|
||||
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
|
||||
/^[A-Z]/.test(tag)
|
||||
) {
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
CacheExpression,
|
||||
createCacheExpression
|
||||
} from './ast'
|
||||
import { isString, isArray } from '@vue/shared'
|
||||
import { isString, isArray, NOOP } from '@vue/shared'
|
||||
import { CompilerError, defaultOnError } from './errors'
|
||||
import {
|
||||
TO_STRING,
|
||||
@@ -68,6 +68,7 @@ export type StructuralDirectiveTransform = (
|
||||
export interface TransformOptions {
|
||||
nodeTransforms?: NodeTransform[]
|
||||
directiveTransforms?: { [name: string]: DirectiveTransform }
|
||||
isBuiltInComponent?: (tag: string) => symbol | void
|
||||
prefixIdentifiers?: boolean
|
||||
hoistStatic?: boolean
|
||||
cacheHandlers?: boolean
|
||||
@@ -110,6 +111,7 @@ function createTransformContext(
|
||||
cacheHandlers = false,
|
||||
nodeTransforms = [],
|
||||
directiveTransforms = {},
|
||||
isBuiltInComponent = NOOP,
|
||||
onError = defaultOnError
|
||||
}: TransformOptions
|
||||
): TransformContext {
|
||||
@@ -132,6 +134,7 @@ function createTransformContext(
|
||||
cacheHandlers,
|
||||
nodeTransforms,
|
||||
directiveTransforms,
|
||||
isBuiltInComponent,
|
||||
onError,
|
||||
parent: null,
|
||||
currentNode: root,
|
||||
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
createObjectExpression,
|
||||
Property
|
||||
} from '../ast'
|
||||
import { PatchFlags, PatchFlagNames, isSymbol, hyphenate } from '@vue/shared'
|
||||
import { PatchFlags, PatchFlagNames, isSymbol } from '@vue/shared'
|
||||
import { createCompilerError, ErrorCodes } from '../errors'
|
||||
import {
|
||||
CREATE_VNODE,
|
||||
@@ -26,11 +26,15 @@ import {
|
||||
MERGE_PROPS,
|
||||
TO_HANDLERS,
|
||||
PORTAL,
|
||||
SUSPENSE,
|
||||
KEEP_ALIVE,
|
||||
BASE_TRANSITION
|
||||
KEEP_ALIVE
|
||||
} from '../runtimeHelpers'
|
||||
import { getInnerRange, isVSlot, toValidAssetId, findProp } from '../utils'
|
||||
import {
|
||||
getInnerRange,
|
||||
isVSlot,
|
||||
toValidAssetId,
|
||||
findProp,
|
||||
isCoreComponent
|
||||
} from '../utils'
|
||||
import { buildSlots } from './vSlot'
|
||||
import { isStaticNode } from './hoistStatic'
|
||||
|
||||
@@ -38,9 +42,6 @@ import { isStaticNode } from './hoistStatic'
|
||||
// import, which should be used instead of a resolveDirective call.
|
||||
const directiveImportMap = new WeakMap<DirectiveNode, symbol>()
|
||||
|
||||
const isBuiltInType = (tag: string, expected: string): boolean =>
|
||||
tag === expected || tag === hyphenate(expected)
|
||||
|
||||
// generate a JavaScript AST for this element's codegen
|
||||
export const transformElement: NodeTransform = (node, context) => {
|
||||
if (
|
||||
@@ -57,10 +58,8 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
// processed and merged.
|
||||
return function postTransformElement() {
|
||||
const { tag, tagType, props } = node
|
||||
const isPortal = isBuiltInType(tag, 'Portal')
|
||||
const isSuspense = isBuiltInType(tag, 'Suspense')
|
||||
const isKeepAlive = isBuiltInType(tag, 'KeepAlive')
|
||||
const isBaseTransition = isBuiltInType(tag, 'BaseTransition')
|
||||
const builtInComponentSymbol =
|
||||
isCoreComponent(tag) || context.isBuiltInComponent(tag)
|
||||
const isComponent = tagType === ElementTypes.COMPONENT
|
||||
|
||||
let hasProps = props.length > 0
|
||||
@@ -96,14 +95,8 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
let nodeType
|
||||
if (dynamicComponent) {
|
||||
nodeType = dynamicComponent
|
||||
} else if (isPortal) {
|
||||
nodeType = context.helper(PORTAL)
|
||||
} else if (isSuspense) {
|
||||
nodeType = context.helper(SUSPENSE)
|
||||
} else if (isKeepAlive) {
|
||||
nodeType = context.helper(KEEP_ALIVE)
|
||||
} else if (isBaseTransition) {
|
||||
nodeType = context.helper(BASE_TRANSITION)
|
||||
} else if (builtInComponentSymbol) {
|
||||
nodeType = context.helper(builtInComponentSymbol)
|
||||
} else if (isComponent) {
|
||||
// user component w/ resolve
|
||||
context.helper(RESOLVE_COMPONENT)
|
||||
@@ -142,7 +135,11 @@ export const transformElement: NodeTransform = (node, context) => {
|
||||
// Portal is not a real component has dedicated handling in the renderer
|
||||
// KeepAlive should not track its own deps so that it can be used inside
|
||||
// Transition
|
||||
if (isComponent && !isPortal && !isKeepAlive) {
|
||||
if (
|
||||
isComponent &&
|
||||
builtInComponentSymbol !== PORTAL &&
|
||||
builtInComponentSymbol !== KEEP_ALIVE
|
||||
) {
|
||||
const { slots, hasDynamicSlots } = buildSlots(node, context)
|
||||
args.push(slots)
|
||||
if (hasDynamicSlots) {
|
||||
|
||||
@@ -27,8 +27,31 @@ import {
|
||||
import { parse } from 'acorn'
|
||||
import { walk } from 'estree-walker'
|
||||
import { TransformContext } from './transform'
|
||||
import { OPEN_BLOCK, MERGE_PROPS, RENDER_SLOT } from './runtimeHelpers'
|
||||
import { isString, isFunction, isObject } from '@vue/shared'
|
||||
import {
|
||||
OPEN_BLOCK,
|
||||
MERGE_PROPS,
|
||||
RENDER_SLOT,
|
||||
PORTAL,
|
||||
SUSPENSE,
|
||||
KEEP_ALIVE,
|
||||
BASE_TRANSITION
|
||||
} from './runtimeHelpers'
|
||||
import { isString, isFunction, isObject, hyphenate } from '@vue/shared'
|
||||
|
||||
export const isBuiltInType = (tag: string, expected: string): boolean =>
|
||||
tag === expected || tag === hyphenate(expected)
|
||||
|
||||
export function isCoreComponent(tag: string): symbol | void {
|
||||
if (isBuiltInType(tag, 'Portal')) {
|
||||
return PORTAL
|
||||
} else if (isBuiltInType(tag, 'Suspense')) {
|
||||
return SUSPENSE
|
||||
} else if (isBuiltInType(tag, 'KeepAlive')) {
|
||||
return KEEP_ALIVE
|
||||
} else if (isBuiltInType(tag, 'BaseTransition')) {
|
||||
return BASE_TRANSITION
|
||||
}
|
||||
}
|
||||
|
||||
// cache node requires
|
||||
// lazy require dependencies so that they don't end up in rollup's dep graph
|
||||
|
||||
Reference in New Issue
Block a user