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 <button is="vue:my-button"></button> <ul is="vue:transition-group" tag="ul"></ul> ```
This commit is contained in:
		
							parent
							
								
									422b13e798
								
							
						
					
					
						commit
						af9e6999e1
					
				@ -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
 | 
			
		||||
 | 
			
		||||
@ -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) {
 | 
			
		||||
      // <button is="vue:xxx">
 | 
			
		||||
      // if not <component>, only is value that starts with "vue:" will be
 | 
			
		||||
      // treated as component by the parse phase and reach here.
 | 
			
		||||
      tag = isProp.value!.content.slice(4)
 | 
			
		||||
    } else {
 | 
			
		||||
      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
 | 
			
		||||
        ])
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -416,8 +423,11 @@ export function buildProps(
 | 
			
		||||
          isStatic = false
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      // skip :is on <component>
 | 
			
		||||
      if (name === 'is' && isComponentTag(tag)) {
 | 
			
		||||
      // skip is on <component>, or is="vue:xxx"
 | 
			
		||||
      if (
 | 
			
		||||
        name === 'is' &&
 | 
			
		||||
        (isComponentTag(tag) || (value && value.content.startsWith('vue:')))
 | 
			
		||||
      ) {
 | 
			
		||||
        continue
 | 
			
		||||
      }
 | 
			
		||||
      properties.push(
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user