From af9e6999e1779f56b5cf827b97310d8e4e1fe5ec Mon Sep 17 00:00:00 2001 From: Evan You Date: Mon, 12 Apr 2021 13:07:59 -0400 Subject: [PATCH] feat: support casting plain element to component via is="vue:xxx" In Vue 3's custom elements interop, we no longer process `is` usage on known native elements as component casting. (ref: https://v3.vuejs.org/guide/migration/custom-elements-interop.html) This introduced the need for `v-is`. However, since it is a directive, its value is considered a JavaScript expression. This makes it awkward to use (e.g. `v-is="'foo'"`) when majority of casting is non-dynamic, and also hinders static analysis when casting to built-in Vue components, e.g. transition-group. This commit adds the ability to cast a native element to a Vue component by simply adding a `vue:` prefix: ```html ``` --- packages/compiler-core/src/parse.ts | 7 +++- .../src/transforms/transformElement.ts | 38 ++++++++++++------- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/packages/compiler-core/src/parse.ts b/packages/compiler-core/src/parse.ts index 77e91935119..3bcf4159d5f 100644 --- a/packages/compiler-core/src/parse.ts +++ b/packages/compiler-core/src/parse.ts @@ -488,7 +488,12 @@ function parseTag( const options = context.options if (!context.inVPre && !options.isCustomElement(tag)) { const hasVIs = props.some( - p => p.type === NodeTypes.DIRECTIVE && p.name === 'is' + p => + p.name === 'is' && + // v-is="xxx" (TODO: deprecate) + (p.type === NodeTypes.DIRECTIVE || + // is="vue:xxx" + (p.value && p.value.content.startsWith('vue:'))) ) if (options.isNativeTag && !hasVIs) { if (!options.isNativeTag(tag)) tagType = ElementTypes.COMPONENT diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 113b03dd856..334304adc13 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -230,21 +230,28 @@ export function resolveComponentType( context: TransformContext, ssr = false ) { - const { tag } = node + let { tag } = node // 1. dynamic component - const isProp = isComponentTag(tag) - ? findProp(node, 'is') - : findDir(node, 'is') + const isExplicitDynamic = isComponentTag(tag) + const isProp = + findProp(node, 'is') || (!isExplicitDynamic && findDir(node, 'is')) if (isProp) { - const exp = - isProp.type === NodeTypes.ATTRIBUTE - ? isProp.value && createSimpleExpression(isProp.value.content, true) - : isProp.exp - if (exp) { - return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [ - exp - ]) + if (!isExplicitDynamic && isProp.type === NodeTypes.ATTRIBUTE) { + //