mirror of
https://github.com/vuejs/babel-plugin-jsx.git
synced 2025-03-15 15:05:18 +08:00
fix: deoptimize slots when a directive is used (#638)
fixes #541 * fix: deoptimize slots when a directive is used * add test * feat: don't resolve directives in scope
This commit is contained in:
parent
a7607de7b8
commit
7277fe4bc4
@ -184,6 +184,11 @@ const resolveDirective = (
|
|||||||
}
|
}
|
||||||
return modelToUse;
|
return modelToUse;
|
||||||
}
|
}
|
||||||
|
const referenceName =
|
||||||
|
'v' + directiveName[0].toUpperCase() + directiveName.slice(1);
|
||||||
|
if (path.scope.references[referenceName]) {
|
||||||
|
return t.identifier(referenceName);
|
||||||
|
}
|
||||||
return t.callExpression(createIdentifier(state, 'resolveDirective'), [
|
return t.callExpression(createIdentifier(state, 'resolveDirective'), [
|
||||||
t.stringLiteral(directiveName),
|
t.stringLiteral(directiveName),
|
||||||
]);
|
]);
|
||||||
|
@ -405,7 +405,26 @@ const transformJSXElement = (
|
|||||||
|
|
||||||
const { optimize = false } = state.opts;
|
const { optimize = false } = state.opts;
|
||||||
|
|
||||||
const slotFlag = path.getData('slotFlag') || SlotFlags.STABLE;
|
// #541 - directives can't be resolved in optimized slots
|
||||||
|
// all parents should be deoptimized
|
||||||
|
if (
|
||||||
|
directives.length &&
|
||||||
|
directives.some(
|
||||||
|
(d) =>
|
||||||
|
d.elements?.[0]?.type === 'CallExpression' &&
|
||||||
|
d.elements[0].callee.type === 'Identifier' &&
|
||||||
|
d.elements[0].callee.name === '_resolveDirective'
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
let currentPath = path;
|
||||||
|
while (currentPath.parentPath?.isJSXElement()) {
|
||||||
|
currentPath = currentPath.parentPath;
|
||||||
|
currentPath.setData('slotFlag', 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const slotFlag = path.getData('slotFlag') ?? SlotFlags.STABLE;
|
||||||
|
const optimizeSlots = optimize && slotFlag !== 0;
|
||||||
let VNodeChild;
|
let VNodeChild;
|
||||||
|
|
||||||
if (children.length > 1 || slots) {
|
if (children.length > 1 || slots) {
|
||||||
@ -431,7 +450,7 @@ const transformJSXElement = (
|
|||||||
? (slots! as t.ObjectExpression).properties
|
? (slots! as t.ObjectExpression).properties
|
||||||
: [t.spreadElement(slots!)]
|
: [t.spreadElement(slots!)]
|
||||||
: []),
|
: []),
|
||||||
optimize &&
|
optimizeSlots &&
|
||||||
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
|
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
|
||||||
].filter(Boolean as any)
|
].filter(Boolean as any)
|
||||||
)
|
)
|
||||||
@ -452,7 +471,7 @@ const transformJSXElement = (
|
|||||||
t.arrayExpression(buildIIFE(path, [child]))
|
t.arrayExpression(buildIIFE(path, [child]))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
optimize &&
|
optimizeSlots &&
|
||||||
(t.objectProperty(
|
(t.objectProperty(
|
||||||
t.identifier('_'),
|
t.identifier('_'),
|
||||||
t.numericLiteral(slotFlag)
|
t.numericLiteral(slotFlag)
|
||||||
@ -490,7 +509,7 @@ const transformJSXElement = (
|
|||||||
t.arrayExpression(buildIIFE(path, [slotId]))
|
t.arrayExpression(buildIIFE(path, [slotId]))
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
optimize &&
|
optimizeSlots &&
|
||||||
(t.objectProperty(
|
(t.objectProperty(
|
||||||
t.identifier('_'),
|
t.identifier('_'),
|
||||||
t.numericLiteral(slotFlag)
|
t.numericLiteral(slotFlag)
|
||||||
@ -517,7 +536,7 @@ const transformJSXElement = (
|
|||||||
VNodeChild = t.objectExpression(
|
VNodeChild = t.objectExpression(
|
||||||
[
|
[
|
||||||
...child.properties,
|
...child.properties,
|
||||||
optimize &&
|
optimizeSlots &&
|
||||||
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
|
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
|
||||||
].filter(Boolean as any)
|
].filter(Boolean as any)
|
||||||
);
|
);
|
||||||
|
@ -63,6 +63,12 @@ _createVNode(_Fragment, null, [_withDirectives(_createVNode(_resolveComponent("A
|
|||||||
}]])]);"
|
}]])]);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`directive in scope > directive in scope 1`] = `
|
||||||
|
"import { resolveComponent as _resolveComponent, createVNode as _createVNode, withDirectives as _withDirectives } from "vue";
|
||||||
|
const vXxx = {};
|
||||||
|
_withDirectives(_createVNode(_resolveComponent("A"), null, null, 512), [[vXxx]]);"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`disable object slot syntax with defaultSlot > defaultSlot 1`] = `
|
exports[`disable object slot syntax with defaultSlot > defaultSlot 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
|
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
|
||||||
_createVNode(_resolveComponent("Badge"), null, {
|
_createVNode(_resolveComponent("Badge"), null, {
|
||||||
@ -153,6 +159,31 @@ exports[`override props single > single 1`] = `
|
|||||||
_createVNode("div", a, null);"
|
_createVNode("div", a, null);"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`passing object slots via JSX children directive in slot > directive in slot 1`] = `
|
||||||
|
"import { Fragment as _Fragment, resolveDirective as _resolveDirective, createVNode as _createVNode, withDirectives as _withDirectives, resolveComponent as _resolveComponent } from "vue";
|
||||||
|
_createVNode(_Fragment, null, [_createVNode(_resolveComponent("A"), null, {
|
||||||
|
default: () => [_withDirectives(_createVNode("div", null, null, 512), [[_resolveDirective("xxx")]]), foo]
|
||||||
|
}), _createVNode(_resolveComponent("A"), null, {
|
||||||
|
default: () => [_createVNode(_resolveComponent("B"), null, {
|
||||||
|
default: () => [_withDirectives(_createVNode("div", null, null, 512), [[_resolveDirective("xxx")]]), foo]
|
||||||
|
})]
|
||||||
|
})]);"
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`passing object slots via JSX children directive in slot, in scope > directive in slot, in scope 1`] = `
|
||||||
|
"import { Fragment as _Fragment, createVNode as _createVNode, withDirectives as _withDirectives, resolveComponent as _resolveComponent } from "vue";
|
||||||
|
const vXxx = {};
|
||||||
|
_createVNode(_Fragment, null, [_createVNode(_resolveComponent("A"), null, {
|
||||||
|
default: () => [_withDirectives(_createVNode("div", null, null, 512), [[vXxx]]), foo],
|
||||||
|
_: 1
|
||||||
|
}), _createVNode(_resolveComponent("A"), null, {
|
||||||
|
default: () => [_createVNode(_resolveComponent("B"), null, {
|
||||||
|
default: () => [_withDirectives(_createVNode("div", null, null, 512), [[vXxx]]), foo],
|
||||||
|
_: 1
|
||||||
|
})]
|
||||||
|
})]);"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`passing object slots via JSX children multiple expressions > multiple expressions 1`] = `
|
exports[`passing object slots via JSX children multiple expressions > multiple expressions 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
|
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
|
||||||
_createVNode(_resolveComponent("A"), null, {
|
_createVNode(_resolveComponent("A"), null, {
|
||||||
@ -161,6 +192,19 @@ _createVNode(_resolveComponent("A"), null, {
|
|||||||
});"
|
});"
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
exports[`passing object slots via JSX children no directive in slot > no directive in slot 1`] = `
|
||||||
|
"import { Fragment as _Fragment, createVNode as _createVNode, resolveComponent as _resolveComponent } from "vue";
|
||||||
|
_createVNode(_Fragment, null, [_createVNode(_resolveComponent("A"), null, {
|
||||||
|
default: () => [_createVNode("div", null, null), foo],
|
||||||
|
_: 1
|
||||||
|
}), _createVNode(_resolveComponent("A"), null, {
|
||||||
|
default: () => [_createVNode(_resolveComponent("B"), null, {
|
||||||
|
default: () => [_createVNode("div", null, null), foo],
|
||||||
|
_: 1
|
||||||
|
})]
|
||||||
|
})]);"
|
||||||
|
`;
|
||||||
|
|
||||||
exports[`passing object slots via JSX children single expression, function expression > single expression, function expression 1`] = `
|
exports[`passing object slots via JSX children single expression, function expression > single expression, function expression 1`] = `
|
||||||
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
|
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
|
||||||
_createVNode(_resolveComponent("A"), null, {
|
_createVNode(_resolveComponent("A"), null, {
|
||||||
|
@ -155,6 +155,13 @@ const transpile = (source: string, options: VueJSXPluginOptions = {}) =>
|
|||||||
</>
|
</>
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'directive in scope',
|
||||||
|
from: `
|
||||||
|
const vXxx = {};
|
||||||
|
<A v-xxx />
|
||||||
|
`,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'vModels',
|
name: 'vModels',
|
||||||
from: '<C v-models={[[foo, ["modifier"]], [bar, "bar", ["modifier1", "modifier2"]]]} />',
|
from: '<C v-models={[[foo, ["modifier"]], [bar, "bar", ["modifier1", "modifier2"]]]} />',
|
||||||
@ -255,6 +262,40 @@ const slotsTests: Test[] = [
|
|||||||
<A>{foo()}</A>;
|
<A>{foo()}</A>;
|
||||||
`,
|
`,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'no directive in slot',
|
||||||
|
from: `
|
||||||
|
<>
|
||||||
|
<A><div />{foo}</A>
|
||||||
|
<A>
|
||||||
|
<B><div />{foo}</B>
|
||||||
|
</A>
|
||||||
|
</>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'directive in slot',
|
||||||
|
from: `
|
||||||
|
<>
|
||||||
|
<A><div v-xxx />{foo}</A>
|
||||||
|
<A>
|
||||||
|
<B><div v-xxx />{foo}</B>
|
||||||
|
</A>
|
||||||
|
</>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'directive in slot, in scope',
|
||||||
|
from: `
|
||||||
|
const vXxx = {};
|
||||||
|
<>
|
||||||
|
<A><div v-xxx />{foo}</A>
|
||||||
|
<A>
|
||||||
|
<B><div v-xxx />{foo}</B>
|
||||||
|
</A>
|
||||||
|
</>
|
||||||
|
`,
|
||||||
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
slotsTests.forEach(({ name, from }) => {
|
slotsTests.forEach(({ name, from }) => {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user