-import { NO, makeMap, isArray } from '@vue/shared'
+import { NO, isArray } from '@vue/shared'
import {
ErrorCodes,
createCompilerError,
import {
assert,
advancePositionWithMutation,
- advancePositionWithClone
+ advancePositionWithClone,
+ isCoreComponent
} from './utils'
import {
Namespace,
} 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] // ['{{', '}}']
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)
) {
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,
export interface TransformOptions {
nodeTransforms?: NodeTransform[]
directiveTransforms?: { [name: string]: DirectiveTransform }
+ isBuiltInComponent?: (tag: string) => symbol | void
prefixIdentifiers?: boolean
hoistStatic?: boolean
cacheHandlers?: boolean
cacheHandlers = false,
nodeTransforms = [],
directiveTransforms = {},
+ isBuiltInComponent = NOOP,
onError = defaultOnError
}: TransformOptions
): TransformContext {
cacheHandlers,
nodeTransforms,
directiveTransforms,
+ isBuiltInComponent,
onError,
parent: null,
currentNode: root,
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,
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'
// 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 (
// 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
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)
// 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) {
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
-import { baseCompile, CompilerOptions, CodegenResult } from '@vue/compiler-core'
+import {
+ baseCompile,
+ CompilerOptions,
+ CodegenResult,
+ isBuiltInType
+} from '@vue/compiler-core'
import { parserOptionsMinimal } from './parserOptionsMinimal'
import { parserOptionsStandard } from './parserOptionsStandard'
import { transformStyle } from './transforms/transformStyle'
import { transformModel } from './transforms/vModel'
import { transformOn } from './transforms/vOn'
import { transformShow } from './transforms/vShow'
+import { TRANSITION, TRANSITION_GROUP } from './runtimeHelpers'
export function compile(
template: string,
on: transformOn,
show: transformShow,
...(options.directiveTransforms || {})
+ },
+ isBuiltInComponent: tag => {
+ if (isBuiltInType(tag, `Transition`)) {
+ return TRANSITION
+ } else if (isBuiltInType(tag, `TransitionGroup`)) {
+ return TRANSITION_GROUP
+ }
}
})
}
export const V_SHOW = Symbol(__DEV__ ? `vShow` : ``)
+export const TRANSITION = Symbol(__DEV__ ? `Transition` : ``)
+export const TRANSITION_GROUP = Symbol(__DEV__ ? `TransitionGroup` : ``)
+
registerRuntimeHelpers({
[V_MODEL_RADIO]: `vModelRadio`,
[V_MODEL_CHECKBOX]: `vModelCheckbox`,
[V_MODEL_DYNAMIC]: `vModelDynamic`,
[V_ON_WITH_MODIFIERS]: `withModifiers`,
[V_ON_WITH_KEYS]: `withKeys`,
- [V_SHOW]: `vShow`
+ [V_SHOW]: `vShow`,
+ [TRANSITION]: `Transition`,
+ [TRANSITION_GROUP]: `TransitionGroup`
})
prevChildren = children
children = slots.default ? slots.default() : []
+ // handle fragment children case, e.g. v-for
+ if (children.length === 1 && children[0].type === Fragment) {
+ children = children[0].children as VNode[]
+ }
+
for (let i = 0; i < children.length; i++) {
const child = children[i]
if (child.key != null) {