From 9454655ee7ee27807b83e6bd940baa931e5dd4ab Mon Sep 17 00:00:00 2001 From: Amour1688 Date: Sun, 12 Jul 2020 10:19:31 +0800 Subject: [PATCH] fix: component doesn't render when variables outside slot --- .../babel-plugin-jsx/src/transform-vue-jsx.ts | 17 +++--- packages/babel-plugin-jsx/src/utils.ts | 8 +++ packages/babel-plugin-jsx/test/index.test.js | 59 ++++++++++++++++--- 3 files changed, 69 insertions(+), 15 deletions(-) diff --git a/packages/babel-plugin-jsx/src/transform-vue-jsx.ts b/packages/babel-plugin-jsx/src/transform-vue-jsx.ts index add2f93..6aa1268 100644 --- a/packages/babel-plugin-jsx/src/transform-vue-jsx.ts +++ b/packages/babel-plugin-jsx/src/transform-vue-jsx.ts @@ -12,6 +12,7 @@ import { transformJSXExpressionContainer, parseDirectives, isFragment, + walksScope, } from './utils'; import { PatchFlags, PatchFlagNames } from './patchFlags'; import { State, ExcludesBoolean } from './'; @@ -22,13 +23,17 @@ const onRE = /^on[^a-z]/; const isOn = (key: string) => onRE.test(key); const transformJSXSpreadAttribute = ( + nodePath: NodePath, path: NodePath, mergeArgs: (t.ObjectProperty | t.Expression)[] ) => { const argument = path.get('argument') as NodePath; const { properties } = argument.node; if (!properties) { - // argument is an Identifier + if (argument.isIdentifier()) { + console.log(isConstant(argument.node), argument.node) + walksScope(nodePath, (argument.node as t.Identifier).name); + } mergeArgs.push(argument.node); } else { mergeArgs.push(t.objectExpression(properties)); @@ -257,7 +262,7 @@ const buildProps = (path: NodePath, state: State) => { } else { // JSXSpreadAttribute hasDynamicKeys = true; - transformJSXSpreadAttribute(prop as NodePath, mergeArgs); + transformJSXSpreadAttribute(path as NodePath, prop as NodePath, mergeArgs); } }); @@ -386,11 +391,7 @@ const transformJSXElement = ( slots } = buildProps(path, state); - const { scope: { bindings } } = path; - - const bindingsReferenced = Object.keys(bindings).some(key => bindings[key].referenced); - - const useOptimate = !(bindingsReferenced && t.isReturnStatement(path.container)); + const useOptimate = path.getData('optimize') !== false; const flagNames = Object.keys(PatchFlagNames) .map(Number) @@ -411,7 +412,7 @@ const transformJSXElement = ( // @ts-ignore compatibleProps ? t.callExpression(state.get('compatibleProps'), [props]) : props, (children.length || slots) ? ( - isComponent && (children.length || slots) + isComponent ? t.objectExpression([ !!children.length && t.objectProperty( t.identifier('default'), diff --git a/packages/babel-plugin-jsx/src/utils.ts b/packages/babel-plugin-jsx/src/utils.ts index 5215da3..58eb701 100644 --- a/packages/babel-plugin-jsx/src/utils.ts +++ b/packages/babel-plugin-jsx/src/utils.ts @@ -274,6 +274,13 @@ const parseDirectives = (args: { }; }; +const walksScope = (path: NodePath, name: string) => { + if (path.scope.hasBinding(name)) { + path.parentPath.setData('optimize', false); + walksScope(path.parentPath, name); + } +} + export { createIdentifier, isDirective, @@ -286,4 +293,5 @@ export { transformJSXExpressionContainer, parseDirectives, isFragment, + walksScope, }; diff --git a/packages/babel-plugin-jsx/test/index.test.js b/packages/babel-plugin-jsx/test/index.test.js index 71a8575..36cbd4e 100644 --- a/packages/babel-plugin-jsx/test/index.test.js +++ b/packages/babel-plugin-jsx/test/index.test.js @@ -266,35 +266,39 @@ describe('Transform JSX', () => { describe('slots', () => { test('with default', () => { const A = (_, { slots }) => ( - <> +
{slots.default()} {slots.foo('val')} - +
); + A.inheritAttrs = false; + const wrapper = mount({ setup() { const slots = { - foo: (val) =>
{val}
, + foo: (val) => val, }; return () => default; }, }); - expect(wrapper.html()).toBe('default
val
'); + expect(wrapper.html()).toBe('
defaultval
'); }); test('without default', () => { const A = (_, { slots }) => ( - <> +
{slots.foo('foo')} - +
); + A.inheritAttrs = false; + const wrapper = mount({ setup() { const slots = { - foo: (val) =>
{val}
, + foo: (val) => val, }; return () => ; }, @@ -349,4 +353,45 @@ describe('PatchFlags', () => { expect(wrapper.classes().sort()).toEqual(['b', 'static'].sort()); }); + + test('variables outside slot', async () => { + const A = { + render() { + return this.$slots.default(); + }, + }; + + A.inheritAttrs = false; + + const wrapper = mount({ + data() { + return { + val: 0, + }; + }, + methods: { + inc() { + this.val += 1; + }, + }, + render() { + const attrs = { + innerHTML: this.val, + }; + return ( + +
+