From b8ffbffaf771c259848743cf4eb1a5ea31795aaa Mon Sep 17 00:00:00 2001 From: Evan You Date: Fri, 27 Mar 2020 16:38:31 -0400 Subject: [PATCH] feat(compiler-core): support v-is see https://github.com/vuejs/rfcs/pull/149 for details --- .../compiler-core/__tests__/parse.spec.ts | 49 +++++++++++++++++++ .../transforms/transformElement.spec.ts | 19 +++++++ packages/compiler-core/src/parse.ts | 6 ++- .../src/transforms/transformElement.ts | 13 +++-- 4 files changed, 82 insertions(+), 5 deletions(-) diff --git a/packages/compiler-core/__tests__/parse.spec.ts b/packages/compiler-core/__tests__/parse.spec.ts index b21288d95c7..4b0992a5f19 100644 --- a/packages/compiler-core/__tests__/parse.spec.ts +++ b/packages/compiler-core/__tests__/parse.spec.ts @@ -646,6 +646,55 @@ describe('compiler: parse', () => { }) }) + test('v-is without `isNativeTag`', () => { + const ast = baseParse( + `
`, + { + isNativeTag: tag => tag === 'div' + } + ) + + expect(ast.children[0]).toMatchObject({ + type: NodeTypes.ELEMENT, + tag: 'div', + tagType: ElementTypes.ELEMENT + }) + + expect(ast.children[1]).toMatchObject({ + type: NodeTypes.ELEMENT, + tag: 'div', + tagType: ElementTypes.COMPONENT + }) + + expect(ast.children[2]).toMatchObject({ + type: NodeTypes.ELEMENT, + tag: 'Comp', + tagType: ElementTypes.COMPONENT + }) + }) + + test('v-is with `isNativeTag`', () => { + const ast = baseParse(`
`) + + expect(ast.children[0]).toMatchObject({ + type: NodeTypes.ELEMENT, + tag: 'div', + tagType: ElementTypes.ELEMENT + }) + + expect(ast.children[1]).toMatchObject({ + type: NodeTypes.ELEMENT, + tag: 'div', + tagType: ElementTypes.COMPONENT + }) + + expect(ast.children[2]).toMatchObject({ + type: NodeTypes.ELEMENT, + tag: 'Comp', + tagType: ElementTypes.COMPONENT + }) + }) + test('custom element', () => { const ast = baseParse('
', { isNativeTag: tag => tag === 'div', diff --git a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts index 43ba48b9a49..6434b51c814 100644 --- a/packages/compiler-core/__tests__/transforms/transformElement.spec.ts +++ b/packages/compiler-core/__tests__/transforms/transformElement.spec.ts @@ -829,6 +829,25 @@ describe('compiler: element transform', () => { } }) }) + + test('v-is', () => { + const { node, root } = parseWithBind(`
`) + expect(root.helpers).toContain(RESOLVE_DYNAMIC_COMPONENT) + expect(node).toMatchObject({ + tag: { + callee: RESOLVE_DYNAMIC_COMPONENT, + arguments: [ + { + type: NodeTypes.SIMPLE_EXPRESSION, + content: `'foo'`, + isStatic: false + } + ] + }, + // should skip v-is runtime check + directives: undefined + }) + }) }) test(' should be forced into blocks', () => { diff --git a/packages/compiler-core/src/parse.ts b/packages/compiler-core/src/parse.ts index a45a7f37b79..11cad7f19a8 100644 --- a/packages/compiler-core/src/parse.ts +++ b/packages/compiler-core/src/parse.ts @@ -451,9 +451,13 @@ function parseTag( let tagType = ElementTypes.ELEMENT const options = context.options if (!context.inPre && !options.isCustomElement(tag)) { - if (options.isNativeTag) { + const hasVIs = props.some( + p => p.type === NodeTypes.DIRECTIVE && p.name === 'is' + ) + if (options.isNativeTag && !hasVIs) { if (!options.isNativeTag(tag)) tagType = ElementTypes.COMPONENT } else if ( + hasVIs || isCoreComponent(tag) || (options.isBuiltInComponent && options.isBuiltInComponent(tag)) || /^[A-Z]/.test(tag) || diff --git a/packages/compiler-core/src/transforms/transformElement.ts b/packages/compiler-core/src/transforms/transformElement.ts index 155c1dcffb3..4ae461caf54 100644 --- a/packages/compiler-core/src/transforms/transformElement.ts +++ b/packages/compiler-core/src/transforms/transformElement.ts @@ -36,7 +36,8 @@ import { toValidAssetId, findProp, isCoreComponent, - isBindKey + isBindKey, + findDir } from '../utils' import { buildSlots } from './vSlot' import { isStaticNode } from './hoistStatic' @@ -202,7 +203,8 @@ export function resolveComponentType( const { tag } = node // 1. dynamic component - const isProp = node.tag === 'component' && findProp(node, 'is') + const isProp = + node.tag === 'component' ? findProp(node, 'is') : findDir(node, 'is') if (isProp) { const exp = isProp.type === NodeTypes.ATTRIBUTE @@ -340,8 +342,11 @@ export function buildProps( if (name === 'once') { continue } - // skip :is on - if (isBind && tag === 'component' && isBindKey(arg, 'is')) { + // skip v-is and :is on + if ( + name === 'is' || + (isBind && tag === 'component' && isBindKey(arg, 'is')) + ) { continue } // skip v-on in SSR compilation