Skip to content

Commit 9454655

Browse files
committed
fix: component doesn't render when variables outside slot
1 parent 5c59e2e commit 9454655

File tree

3 files changed

+69
-15
lines changed

3 files changed

+69
-15
lines changed

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

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import {
1212
transformJSXExpressionContainer,
1313
parseDirectives,
1414
isFragment,
15+
walksScope,
1516
} from './utils';
1617
import { PatchFlags, PatchFlagNames } from './patchFlags';
1718
import { State, ExcludesBoolean } from './';
@@ -22,13 +23,17 @@ const onRE = /^on[^a-z]/;
2223
const isOn = (key: string) => onRE.test(key);
2324

2425
const transformJSXSpreadAttribute = (
26+
nodePath: NodePath,
2527
path: NodePath<t.JSXSpreadAttribute>,
2628
mergeArgs: (t.ObjectProperty | t.Expression)[]
2729
) => {
2830
const argument = path.get('argument') as NodePath<t.ObjectExpression>;
2931
const { properties } = argument.node;
3032
if (!properties) {
31-
// argument is an Identifier
33+
if (argument.isIdentifier()) {
34+
console.log(isConstant(argument.node), argument.node)
35+
walksScope(nodePath, (argument.node as t.Identifier).name);
36+
}
3237
mergeArgs.push(argument.node);
3338
} else {
3439
mergeArgs.push(t.objectExpression(properties));
@@ -257,7 +262,7 @@ const buildProps = (path: NodePath<t.JSXElement>, state: State) => {
257262
} else {
258263
// JSXSpreadAttribute
259264
hasDynamicKeys = true;
260-
transformJSXSpreadAttribute(prop as NodePath<t.JSXSpreadAttribute>, mergeArgs);
265+
transformJSXSpreadAttribute(path as NodePath, prop as NodePath<t.JSXSpreadAttribute>, mergeArgs);
261266
}
262267
});
263268

@@ -386,11 +391,7 @@ const transformJSXElement = (
386391
slots
387392
} = buildProps(path, state);
388393

389-
const { scope: { bindings } } = path;
390-
391-
const bindingsReferenced = Object.keys(bindings).some(key => bindings[key].referenced);
392-
393-
const useOptimate = !(bindingsReferenced && t.isReturnStatement(path.container));
394+
const useOptimate = path.getData('optimize') !== false;
394395

395396
const flagNames = Object.keys(PatchFlagNames)
396397
.map(Number)
@@ -411,7 +412,7 @@ const transformJSXElement = (
411412
// @ts-ignore
412413
compatibleProps ? t.callExpression(state.get('compatibleProps'), [props]) : props,
413414
(children.length || slots) ? (
414-
isComponent && (children.length || slots)
415+
isComponent
415416
? t.objectExpression([
416417
!!children.length && t.objectProperty(
417418
t.identifier('default'),

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,13 @@ const parseDirectives = (args: {
274274
};
275275
};
276276

277+
const walksScope = (path: NodePath, name: string) => {
278+
if (path.scope.hasBinding(name)) {
279+
path.parentPath.setData('optimize', false);
280+
walksScope(path.parentPath, name);
281+
}
282+
}
283+
277284
export {
278285
createIdentifier,
279286
isDirective,
@@ -286,4 +293,5 @@ export {
286293
transformJSXExpressionContainer,
287294
parseDirectives,
288295
isFragment,
296+
walksScope,
289297
};

packages/babel-plugin-jsx/test/index.test.js

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -266,35 +266,39 @@ describe('Transform JSX', () => {
266266
describe('slots', () => {
267267
test('with default', () => {
268268
const A = (_, { slots }) => (
269-
<>
269+
<div>
270270
{slots.default()}
271271
{slots.foo('val')}
272-
</>
272+
</div>
273273
);
274274

275+
A.inheritAttrs = false;
276+
275277
const wrapper = mount({
276278
setup() {
277279
const slots = {
278-
foo: (val) => <div>{val}</div>,
280+
foo: (val) => val,
279281
};
280282
return () => <A vSlots={slots}><span>default</span></A>;
281283
},
282284
});
283285

284-
expect(wrapper.html()).toBe('<span>default</span><div>val</div>');
286+
expect(wrapper.html()).toBe('<div><span>default</span>val</div>');
285287
});
286288

287289
test('without default', () => {
288290
const A = (_, { slots }) => (
289-
<>
291+
<div>
290292
{slots.foo('foo')}
291-
</>
293+
</div>
292294
);
293295

296+
A.inheritAttrs = false;
297+
294298
const wrapper = mount({
295299
setup() {
296300
const slots = {
297-
foo: (val) => <div>{val}</div>,
301+
foo: (val) => val,
298302
};
299303
return () => <A vSlots={slots} />;
300304
},
@@ -349,4 +353,45 @@ describe('PatchFlags', () => {
349353

350354
expect(wrapper.classes().sort()).toEqual(['b', 'static'].sort());
351355
});
356+
357+
test('variables outside slot', async () => {
358+
const A = {
359+
render() {
360+
return this.$slots.default();
361+
},
362+
};
363+
364+
A.inheritAttrs = false;
365+
366+
const wrapper = mount({
367+
data() {
368+
return {
369+
val: 0,
370+
};
371+
},
372+
methods: {
373+
inc() {
374+
this.val += 1;
375+
},
376+
},
377+
render() {
378+
const attrs = {
379+
innerHTML: this.val,
380+
};
381+
return (
382+
<A inc={this.inc}>
383+
<div>
384+
<textarea id="textarea" {...attrs} />
385+
</div>
386+
<button id="button" onClick={this.inc}>+1</button>
387+
</A>
388+
);
389+
},
390+
});
391+
392+
expect(wrapper.get('#textarea').element.innerHTML).toBe('0');
393+
394+
await wrapper.get('#button').trigger('click');
395+
expect(wrapper.get('#textarea').element.innerHTML).toBe('1');
396+
});
352397
});

0 commit comments

Comments
 (0)