fix(babel-plugin-jsx):

prevent transform aliased Fragment and KeepAlive's children to slots
This commit is contained in:
zhiyuanzmj
2025-05-23 23:16:11 +08:00
parent a72bc11ed8
commit 77fe056dda
4 changed files with 51 additions and 10 deletions

View File

@ -119,6 +119,31 @@ export default declare<VueJSXPluginOptions, BabelCore.PluginObj<State>>(
return isSlot; return isSlot;
}); });
} }
const vueImportMap: Record<
string,
(t.MemberExpression | t.Identifier)[]
> = {};
state.set('vueImportMap', vueImportMap);
path.node.body.forEach((statement) => {
if (t.isImportDeclaration(statement)) {
const { source, specifiers } = statement;
if (source.value === 'vue') {
specifiers.forEach((specifier) => {
if (
t.isImportSpecifier(specifier) &&
t.isIdentifier(specifier.imported)
) {
const name = specifier.imported.name;
if (!vueImportMap[name]) {
vueImportMap[name] = [];
}
vueImportMap[name].push(specifier.local);
}
});
}
}
});
} else { } else {
// var _vue = require('vue'); // var _vue = require('vue');
let sourceName: t.Identifier; let sourceName: t.Identifier;

View File

@ -30,11 +30,23 @@ export const isDirective = (src: string): boolean =>
/** /**
* Should transformed to slots * Should transformed to slots
* @param tag string * @param tag string
* @param state State
* @returns boolean * @returns boolean
*/ */
// if _Fragment is already imported, it will end with number // if _Fragment is already imported, it will end with number
export const shouldTransformedToSlots = (tag: string) => export const shouldTransformedToSlots = (tag: string, state?: State) => {
!(tag.match(RegExp(`^_?${FRAGMENT}\\d*$`)) || tag === KEEP_ALIVE); if (state) {
const vueImportMap = state.get('vueImportMap');
for (const name of [FRAGMENT, KEEP_ALIVE]) {
if (vueImportMap[name]) {
if(vueImportMap[name].some((id: t.Identifier) => id.name === tag)){
return false
}
}
}
}
return !(tag.match(RegExp(`^_?${FRAGMENT}\\d*$`)) || tag === KEEP_ALIVE);
};
/** /**
* Check if a Node is a component * Check if a Node is a component
@ -57,7 +69,7 @@ export const checkIsComponent = (
return ( return (
!state.opts.isCustomElement?.(tag) && !state.opts.isCustomElement?.(tag) &&
shouldTransformedToSlots(tag) && shouldTransformedToSlots(tag, state) &&
!isHTMLTag(tag) && !isHTMLTag(tag) &&
!isSVGTag(tag) !isSVGTag(tag)
); );

View File

@ -1,9 +1,10 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
exports[`_Fragment already imported > _Fragment already imported 1`] = ` exports[`_Fragment already imported > _Fragment already imported 1`] = `
"import { Fragment as _Fragment, Fragment as _Fragment2, createTextVNode as _createTextVNode, createVNode as _createVNode } from 'vue'; "import { Fragment as _Fragment, Fragment as _FragmentA, Fragment as _Fragment2, createTextVNode as _createTextVNode, createVNode as _createVNode } from 'vue';
const Root1 = () => _createVNode(_Fragment2, null, [_createTextVNode("root1")]); const Root1 = () => _createVNode(_Fragment2, null, [_createTextVNode("root1")]);
const Root2 = () => _createVNode(_Fragment, null, [_createTextVNode("root2")]);" const Root2 = () => _createVNode(_Fragment, null, [_createTextVNode("root2")]);
const Root3 = () => _createVNode(_FragmentA, null, [_createTextVNode("root3")]);"
`; `;
exports[`MereProps Order > MereProps Order 1`] = ` exports[`MereProps Order > MereProps Order 1`] = `
@ -130,8 +131,9 @@ _createVNode("foo", null, [_createVNode("span", null, [_createTextVNode("foo")])
`; `;
exports[`named import specifier \`Keep Alive\` > named import specifier \`Keep Alive\` 1`] = ` exports[`named import specifier \`Keep Alive\` > named import specifier \`Keep Alive\` 1`] = `
"import { KeepAlive, createTextVNode as _createTextVNode, createVNode as _createVNode } from 'vue'; "import { KeepAlive, KeepAlive as KeepAliveA, createTextVNode as _createTextVNode, createVNode as _createVNode } from 'vue';
_createVNode(KeepAlive, null, [_createTextVNode("123")]);" const Root1 = _createVNode(KeepAlive, null, [_createTextVNode("root1")]);
const Root2 = _createVNode(KeepAliveA, null, [_createTextVNode("root2")]);"
`; `;
exports[`namespace specifier \`Keep Alive\` > namespace specifier \`Keep Alive\` 1`] = ` exports[`namespace specifier \`Keep Alive\` > namespace specifier \`Keep Alive\` 1`] = `

View File

@ -173,9 +173,10 @@ const transpile = (source: string, options: VueJSXPluginOptions = {}) =>
{ {
name: 'named import specifier `Keep Alive`', name: 'named import specifier `Keep Alive`',
from: ` from: `
import { KeepAlive } from 'vue'; import { KeepAlive, KeepAlive as KeepAliveA } from 'vue';
<KeepAlive>123</KeepAlive> const Root1 = <KeepAlive>root1</KeepAlive>
const Root2 = <KeepAliveA>root2</KeepAliveA>
`, `,
}, },
{ {
@ -353,9 +354,10 @@ const fragmentTests = [
{ {
name: '_Fragment already imported', name: '_Fragment already imported',
from: ` from: `
import { Fragment as _Fragment } from 'vue' import { Fragment as _Fragment, Fragment as _FragmentA } from 'vue'
const Root1 = () => <>root1</> const Root1 = () => <>root1</>
const Root2 = () => <_Fragment>root2</_Fragment> const Root2 = () => <_Fragment>root2</_Fragment>
const Root3 = () => <_FragmentA>root3</_FragmentA>
`, `,
}, },
]; ];