Skip to content

Commit dd7647a

Browse files
committed
feat: emit $stable instead of slotFlags
1 parent 3978eef commit dd7647a

File tree

6 files changed

+161
-110
lines changed

6 files changed

+161
-110
lines changed

packages/babel-plugin-jsx/src/slotFlags.ts

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,55 +26,65 @@ const enum SlotFlags {
2626
export default SlotFlags;
2727

2828
export function determineSlotFlags(
29-
expression: t.ObjectExpression,
29+
expression: t.ObjectExpression | t.Identifier,
3030
slotFlag: SlotFlags
3131
) {
3232
let hasDynamicSlots = false;
3333
let hasForwardedSlots = false;
3434

35-
for (const property of expression.properties) {
36-
// { ...slots } (forwarded)
37-
if (
38-
t.isSpreadElement(property) &&
39-
t.isIdentifier(property.argument) &&
40-
property.argument.name === 'slots'
41-
) {
42-
hasForwardedSlots = true;
43-
continue;
44-
}
45-
46-
// { ...somethingElse } or { [name]: () => {} } (dynamic)
47-
if (t.isSpreadElement(property) || property.computed) {
48-
hasDynamicSlots = true;
49-
break;
50-
}
35+
if (t.isObjectExpression(expression)) {
36+
for (const property of expression.properties) {
37+
// { ...slots } (forwarded)
38+
if (
39+
t.isSpreadElement(property) &&
40+
t.isIdentifier(property.argument) &&
41+
property.argument.name === 'slots'
42+
) {
43+
hasForwardedSlots = true;
44+
continue;
45+
}
5146

52-
// { name () {} } (stable)
53-
if (!t.isObjectProperty(property)) continue;
47+
// { ...somethingElse } or { [name]: () => {} } (dynamic)
48+
if (t.isSpreadElement(property) || property.computed) {
49+
hasDynamicSlots = true;
50+
break;
51+
}
5452

55-
// { name: slots.foo } (forwarded)
56-
if (
57-
t.isMemberExpression(property.value) &&
58-
t.isIdentifier(property.value.object) &&
59-
property.value.object.name === 'slots'
60-
) {
61-
hasForwardedSlots = true;
62-
continue;
63-
}
53+
// { name () {} } (stable)
54+
if (!t.isObjectProperty(property)) continue;
6455

65-
// { name: cond ? a : b }
66-
if (t.isConditional(property.value)) {
67-
// { name: slots.foo ? a : b } (forwarded)
56+
// { name: slots.foo } (forwarded)
6857
if (
69-
t.isMemberExpression(property.value.test) &&
70-
t.isIdentifier(property.value.test.object) &&
71-
property.value.test.object.name === 'slots'
58+
t.isMemberExpression(property.value) &&
59+
t.isIdentifier(property.value.object) &&
60+
property.value.object.name === 'slots'
7261
) {
7362
hasForwardedSlots = true;
7463
continue;
7564
}
65+
66+
// { name: cond ? a : b }
67+
if (t.isConditional(property.value)) {
68+
// { name: slots.foo ? a : b } (forwarded)
69+
if (
70+
t.isMemberExpression(property.value.test) &&
71+
t.isIdentifier(property.value.test.object) &&
72+
property.value.test.object.name === 'slots'
73+
) {
74+
hasForwardedSlots = true;
75+
continue;
76+
}
77+
hasDynamicSlots = true;
78+
break;
79+
}
80+
}
81+
} else {
82+
if (expression.name === 'slots') {
83+
// v-slots={ slots }
84+
hasForwardedSlots = true;
85+
} else {
86+
// v-slots={ somethingElse }
7687
hasDynamicSlots = true;
77-
break;
7888
}
7989
}
8090

@@ -84,3 +94,10 @@ export function determineSlotFlags(
8494
? SlotFlags.FORWARDED
8595
: slotFlag;
8696
}
97+
98+
export function renderSlotFlags(slotFlag: SlotFlags) {
99+
return (
100+
(slotFlag === SlotFlags.STABLE || slotFlag === SlotFlags.FORWARDED) &&
101+
t.objectProperty(t.identifier('$stable'), t.booleanLiteral(true))
102+
);
103+
}

packages/babel-plugin-jsx/src/transform-vue-jsx.ts

Lines changed: 14 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ import {
1818
transformText,
1919
walksScope,
2020
} from './utils';
21-
import SlotFlags, { determineSlotFlags } from './slotFlags';
21+
import SlotFlags, { determineSlotFlags, renderSlotFlags } from './slotFlags';
2222
import { PatchFlags } from './patchFlags';
2323
import parseDirectives from './parseDirectives';
2424
import type { Slots, State } from './interface';
@@ -489,22 +489,19 @@ const transformJSXElement = (
489489
);
490490
}
491491
if (slots) {
492+
slotFlag = determineSlotFlags(slots, slotFlag);
492493
if (t.isObjectExpression(slots)) {
493-
slotFlag = determineSlotFlags(slots, slotFlag);
494494
VNodeChild.properties.push(...slots.properties);
495495
} else {
496-
slotFlag =
497-
slotFlag === SlotFlags.DYNAMIC
498-
? slotFlag
499-
: slots.name === 'slots'
500-
? SlotFlags.FORWARDED
501-
: SlotFlags.DYNAMIC;
502496
VNodeChild.properties.push(t.spreadElement(slots));
503497
}
504498
}
505-
if (optimize) {
499+
if (
500+
optimize &&
501+
(slotFlag === SlotFlags.STABLE || slotFlag === SlotFlags.FORWARDED)
502+
) {
506503
VNodeChild.properties.push(
507-
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag))
504+
t.objectProperty(t.identifier('$stable'), t.booleanLiteral(true))
508505
);
509506
}
510507
}
@@ -523,8 +520,7 @@ const transformJSXElement = (
523520
t.arrayExpression(buildIIFE(path, [child]))
524521
)
525522
),
526-
optimize &&
527-
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
523+
optimize && renderSlotFlags(slotFlag),
528524
].filter((v) => !!v)
529525
);
530526
if (t.isIdentifier(child) && isComponent) {
@@ -559,8 +555,7 @@ const transformJSXElement = (
559555
t.arrayExpression(buildIIFE(path, [slotId]))
560556
)
561557
),
562-
optimize &&
563-
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
558+
optimize && renderSlotFlags(slotFlag),
564559
].filter((v) => !!v)
565560
);
566561
const assignment = t.assignmentExpression('=', slotId, child);
@@ -579,18 +574,15 @@ const transformJSXElement = (
579574
VNodeChild = t.objectExpression(
580575
[
581576
t.objectProperty(t.identifier('default'), child),
582-
optimize &&
583-
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
577+
optimize && renderSlotFlags(slotFlag),
584578
].filter((v) => !!v)
585579
);
586580
} else if (t.isObjectExpression(child)) {
587581
slotFlag = determineSlotFlags(child, slotFlag);
588582
VNodeChild = t.objectExpression(
589-
[
590-
...child.properties,
591-
optimize &&
592-
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
593-
].filter((v) => !!v)
583+
[...child.properties, optimize && renderSlotFlags(slotFlag)].filter(
584+
(v) => !!v
585+
)
594586
);
595587
} else {
596588
VNodeChild = t.arrayExpression([child]);
@@ -601,8 +593,7 @@ const transformJSXElement = (
601593
t.identifier('default'),
602594
t.arrowFunctionExpression([], VNodeChild)
603595
),
604-
optimize &&
605-
t.objectProperty(t.identifier('_'), t.numericLiteral(slotFlag)),
596+
optimize && renderSlotFlags(slotFlag),
606597
].filter((v) => !!v)
607598
);
608599
}

packages/babel-plugin-jsx/test/__snapshots__/slotFlags.test.ts.snap

Lines changed: 45 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@
33
exports[`dynamic slots 'computed key' 1`] = `
44
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
55
_createVNode(_resolveComponent("A"), null, {
6-
[name]: () => {},
7-
_: 2
6+
[name]: () => {}
87
}, 1024);"
98
`;
109

@@ -19,72 +18,94 @@ _createVNode(_resolveComponent("A"), null, {
1918
exports[`dynamic slots 'conditional value' 1`] = `
2019
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
2120
_createVNode(_resolveComponent("A"), null, {
22-
default: foo ? () => {} : undefined,
23-
_: 2
21+
default: foo ? () => {} : undefined
2422
}, 1024);"
2523
`;
2624

27-
exports[`dynamic slots 'nested slots' 1`] = `
28-
"import { Fragment as _Fragment, createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
25+
exports[`dynamic slots 'spread and computed key' 1`] = `
26+
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
2927
_createVNode(_resolveComponent("A"), null, {
30-
foo: ({
31-
bar
32-
}) => _createVNode(_resolveComponent("B"), null, {
33-
foo: () => {
34-
// dynamic
35-
return _createElementVNode(_Fragment, null, [bar], 1024);
36-
},
37-
_: 2
38-
}, 1024),
39-
_: 1
40-
});"
28+
...slots,
29+
[name]: () => {}
30+
}, 1024);"
31+
`;
32+
33+
exports[`dynamic slots 'spread and conditional value' 1`] = `
34+
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
35+
_createVNode(_resolveComponent("A"), null, {
36+
...slots,
37+
default: foo ? () => {} : undefined
38+
}, 1024);"
4139
`;
4240

4341
exports[`forwarded slots 'conditional on slot existence' 1`] = `
4442
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
4543
_createVNode(_resolveComponent("A"), null, {
4644
default: slots.default ? slots.default() : undefined,
47-
_: 3
45+
$stable: true
4846
});"
4947
`;
5048

5149
exports[`forwarded slots 'simple forward' 1`] = `
5250
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
5351
_createVNode(_resolveComponent("A"), null, {
5452
foo: slots.foo,
55-
_: 3
53+
$stable: true
5654
});"
5755
`;
5856

5957
exports[`forwarded slots 'spread all' 1`] = `
6058
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
6159
_createVNode(_resolveComponent("A"), null, {
6260
...slots,
63-
_: 3
61+
$stable: true
6462
});"
6563
`;
6664

67-
exports[`forwarded slots 'spread and add' 1`] = `
65+
exports[`forwarded slots 'spread and add stable' 1`] = `
6866
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
6967
_createVNode(_resolveComponent("A"), null, {
7068
...slots,
7169
foo: () => {},
72-
_: 3
70+
$stable: true
71+
});"
72+
`;
73+
74+
exports[`forwarded slots 'spread and conditional' 1`] = `
75+
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
76+
_createVNode(_resolveComponent("A"), null, {
77+
...slots,
78+
default: slots.default ? slots.default() : undefined,
79+
$stable: true
7380
});"
7481
`;
7582

7683
exports[`forwarded slots 'v-slots passthrough' 1`] = `
7784
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
7885
_createVNode(_resolveComponent("A"), null, {
7986
...slots,
80-
_: 3
87+
$stable: true
8188
});"
8289
`;
8390

8491
exports[`stable slots 'basic' 1`] = `
8592
"import { resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
8693
_createVNode(_resolveComponent("A"), null, {
8794
default: () => {},
88-
_: 1
95+
$stable: true
96+
});"
97+
`;
98+
99+
exports[`stable slots 'nested slots' 1`] = `
100+
"import { Fragment as _Fragment, createElementVNode as _createElementVNode, resolveComponent as _resolveComponent, createVNode as _createVNode } from "vue";
101+
_createVNode(_resolveComponent("A"), null, {
102+
foo: ({
103+
bar
104+
}) => _createVNode(_resolveComponent("B"), null, {
105+
foo: () => {
106+
return _createElementVNode(_Fragment, null, [bar], 1024);
107+
}
108+
}, 1024),
109+
$stable: true
89110
});"
90111
`;

0 commit comments

Comments
 (0)