Skip to content

Commit b8ffbff

Browse files
committed
feat(compiler-core): support v-is
see vuejs/rfcs#149 for details
1 parent d777ac6 commit b8ffbff

File tree

4 files changed

+82
-5
lines changed

4 files changed

+82
-5
lines changed

packages/compiler-core/__tests__/parse.spec.ts

+49
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,55 @@ describe('compiler: parse', () => {
646646
})
647647
})
648648

649+
test('v-is without `isNativeTag`', () => {
650+
const ast = baseParse(
651+
`<div></div><div v-is="'foo'"></div><Comp></Comp>`,
652+
{
653+
isNativeTag: tag => tag === 'div'
654+
}
655+
)
656+
657+
expect(ast.children[0]).toMatchObject({
658+
type: NodeTypes.ELEMENT,
659+
tag: 'div',
660+
tagType: ElementTypes.ELEMENT
661+
})
662+
663+
expect(ast.children[1]).toMatchObject({
664+
type: NodeTypes.ELEMENT,
665+
tag: 'div',
666+
tagType: ElementTypes.COMPONENT
667+
})
668+
669+
expect(ast.children[2]).toMatchObject({
670+
type: NodeTypes.ELEMENT,
671+
tag: 'Comp',
672+
tagType: ElementTypes.COMPONENT
673+
})
674+
})
675+
676+
test('v-is with `isNativeTag`', () => {
677+
const ast = baseParse(`<div></div><div v-is="'foo'"></div><Comp></Comp>`)
678+
679+
expect(ast.children[0]).toMatchObject({
680+
type: NodeTypes.ELEMENT,
681+
tag: 'div',
682+
tagType: ElementTypes.ELEMENT
683+
})
684+
685+
expect(ast.children[1]).toMatchObject({
686+
type: NodeTypes.ELEMENT,
687+
tag: 'div',
688+
tagType: ElementTypes.COMPONENT
689+
})
690+
691+
expect(ast.children[2]).toMatchObject({
692+
type: NodeTypes.ELEMENT,
693+
tag: 'Comp',
694+
tagType: ElementTypes.COMPONENT
695+
})
696+
})
697+
649698
test('custom element', () => {
650699
const ast = baseParse('<div></div><comp></comp>', {
651700
isNativeTag: tag => tag === 'div',

packages/compiler-core/__tests__/transforms/transformElement.spec.ts

+19
Original file line numberDiff line numberDiff line change
@@ -829,6 +829,25 @@ describe('compiler: element transform', () => {
829829
}
830830
})
831831
})
832+
833+
test('v-is', () => {
834+
const { node, root } = parseWithBind(`<div v-is="'foo'" />`)
835+
expect(root.helpers).toContain(RESOLVE_DYNAMIC_COMPONENT)
836+
expect(node).toMatchObject({
837+
tag: {
838+
callee: RESOLVE_DYNAMIC_COMPONENT,
839+
arguments: [
840+
{
841+
type: NodeTypes.SIMPLE_EXPRESSION,
842+
content: `'foo'`,
843+
isStatic: false
844+
}
845+
]
846+
},
847+
// should skip v-is runtime check
848+
directives: undefined
849+
})
850+
})
832851
})
833852

834853
test('<svg> should be forced into blocks', () => {

packages/compiler-core/src/parse.ts

+5-1
Original file line numberDiff line numberDiff line change
@@ -451,9 +451,13 @@ function parseTag(
451451
let tagType = ElementTypes.ELEMENT
452452
const options = context.options
453453
if (!context.inPre && !options.isCustomElement(tag)) {
454-
if (options.isNativeTag) {
454+
const hasVIs = props.some(
455+
p => p.type === NodeTypes.DIRECTIVE && p.name === 'is'
456+
)
457+
if (options.isNativeTag && !hasVIs) {
455458
if (!options.isNativeTag(tag)) tagType = ElementTypes.COMPONENT
456459
} else if (
460+
hasVIs ||
457461
isCoreComponent(tag) ||
458462
(options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||
459463
/^[A-Z]/.test(tag) ||

packages/compiler-core/src/transforms/transformElement.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ import {
3636
toValidAssetId,
3737
findProp,
3838
isCoreComponent,
39-
isBindKey
39+
isBindKey,
40+
findDir
4041
} from '../utils'
4142
import { buildSlots } from './vSlot'
4243
import { isStaticNode } from './hoistStatic'
@@ -202,7 +203,8 @@ export function resolveComponentType(
202203
const { tag } = node
203204

204205
// 1. dynamic component
205-
const isProp = node.tag === 'component' && findProp(node, 'is')
206+
const isProp =
207+
node.tag === 'component' ? findProp(node, 'is') : findDir(node, 'is')
206208
if (isProp) {
207209
const exp =
208210
isProp.type === NodeTypes.ATTRIBUTE
@@ -340,8 +342,11 @@ export function buildProps(
340342
if (name === 'once') {
341343
continue
342344
}
343-
// skip :is on <component>
344-
if (isBind && tag === 'component' && isBindKey(arg, 'is')) {
345+
// skip v-is and :is on <component>
346+
if (
347+
name === 'is' ||
348+
(isBind && tag === 'component' && isBindKey(arg, 'is'))
349+
) {
345350
continue
346351
}
347352
// skip v-on in SSR compilation

0 commit comments

Comments
 (0)