diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts index 8c342b0516d4..f793ec6d34ee 100644 --- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts +++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts @@ -133,6 +133,7 @@ export default class InlineComponentWrapper extends Wrapper { const { component } = renderer; const name = this.var; + block.add_variable(name); const component_opts = x`{}` as ObjectExpression; @@ -417,7 +418,7 @@ export default class InlineComponentWrapper extends Wrapper { } if (${switch_value}) { - var ${name} = new ${switch_value}(${switch_props}(#ctx)); + ${name} = new ${switch_value}(${switch_props}(#ctx)); ${munged_bindings} ${munged_handlers} @@ -495,7 +496,7 @@ export default class InlineComponentWrapper extends Wrapper { ${(this.node.attributes.length > 0 || this.node.bindings.length > 0) && b` ${props && b`let ${props} = ${attribute_object};`}`} ${statements} - const ${name} = new ${expression}(${component_opts}); + ${name} = new ${expression}(${component_opts}); ${munged_bindings} ${munged_handlers} diff --git a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts index 2e9fae1f05cd..078eb1839de8 100644 --- a/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts +++ b/src/compiler/compile/render_dom/wrappers/shared/bind_this.ts @@ -3,6 +3,7 @@ import Component from '../../../Component'; import Block from '../../Block'; import BindingWrapper from '../Element/Binding'; import { Identifier } from 'estree'; +import { compare_node } from '../../../utils/compare_node'; export default function bind_this(component: Component, block: Block, binding: BindingWrapper, variable: Identifier) { const fn = component.get_unique_name(`${variable.name}_binding`); @@ -35,13 +36,26 @@ export default function bind_this(component: Component, block: Block, binding: B } `); + const alias_map = new Map(); const args = []; - for (const id of params) { - args.push(id); + for (let id of params) { + const value = block.renderer.reference(id.name); + let found = false; if (block.variables.has(id.name)) { - if (block.renderer.context_lookup.get(id.name).is_contextual) continue; + let alias = id.name; + for ( + let i = 1; + block.variables.has(alias) && !compare_node(block.variables.get(alias).init, value); + alias = `${id.name}_${i++}` + ); + alias_map.set(alias, id.name); + id = { type: 'Identifier', name: alias }; + found = block.variables.has(alias); + } + args.push(id); + if (!found) { + block.add_variable(id, value); } - block.add_variable(id, block.renderer.reference(id.name)); } const assign = block.get_unique_name(`assign_${variable.name}`); @@ -52,8 +66,8 @@ export default function bind_this(component: Component, block: Block, binding: B const ${unassign} = () => ${callee}(null, ${args}); `); - const condition = Array.from(params) - .map(name => x`${name} !== ${block.renderer.reference(name.name)}`) + const condition = Array.from(args) + .map(name => x`${name} !== ${block.renderer.reference(alias_map.get(name.name) || name.name)}`) .reduce((lhs, rhs) => x`${lhs} || ${rhs}`); // we push unassign and unshift assign so that references are @@ -62,7 +76,7 @@ export default function bind_this(component: Component, block: Block, binding: B block.chunks.update.push(b` if (${condition}) { ${unassign}(); - ${args.map(a => b`${a} = ${block.renderer.reference(a.name)}`)}; + ${args.map(a => b`${a} = ${block.renderer.reference(alias_map.get(a.name) || a.name)}`)}; ${assign}(); }` ); diff --git a/src/compiler/compile/utils/compare_node.ts b/src/compiler/compile/utils/compare_node.ts new file mode 100644 index 000000000000..ead79a5ea088 --- /dev/null +++ b/src/compiler/compile/utils/compare_node.ts @@ -0,0 +1,19 @@ +import { Node, Literal, Identifier, MemberExpression } from "estree"; + +export function compare_node(a: Node | void, b: Node | void) { + if (a === b) return true; + if (!a || !b) return false; + if (a.type !== b.type) return false; + switch (a.type) { + case "Identifier": + return a.name === (b as Identifier).name; + case "MemberExpression": + return ( + compare_node(a.object, (b as MemberExpression).object) && + compare_node(a.property, (b as MemberExpression).property) && + a.computed === (b as MemberExpression).computed + ); + case 'Literal': + return a.value === (b as Literal).value; + } +} diff --git a/test/js/samples/component-static-array/expected.js b/test/js/samples/component-static-array/expected.js index 44e8dbfe330f..0ecb0f32ba08 100644 --- a/test/js/samples/component-static-array/expected.js +++ b/test/js/samples/component-static-array/expected.js @@ -12,8 +12,9 @@ import { } from "svelte/internal"; function create_fragment(ctx) { + let nested; let current; - const nested = new /*Nested*/ ctx[0]({ props: { foo: [1, 2, 3] } }); + nested = new /*Nested*/ ctx[0]({ props: { foo: [1, 2, 3] } }); return { c() { diff --git a/test/js/samples/component-static-immutable/expected.js b/test/js/samples/component-static-immutable/expected.js index a7dd8128fa94..b0c416541334 100644 --- a/test/js/samples/component-static-immutable/expected.js +++ b/test/js/samples/component-static-immutable/expected.js @@ -12,8 +12,9 @@ import { } from "svelte/internal"; function create_fragment(ctx) { + let nested; let current; - const nested = new /*Nested*/ ctx[0]({ props: { foo: "bar" } }); + nested = new /*Nested*/ ctx[0]({ props: { foo: "bar" } }); return { c() { diff --git a/test/js/samples/component-static-immutable2/expected.js b/test/js/samples/component-static-immutable2/expected.js index a7dd8128fa94..b0c416541334 100644 --- a/test/js/samples/component-static-immutable2/expected.js +++ b/test/js/samples/component-static-immutable2/expected.js @@ -12,8 +12,9 @@ import { } from "svelte/internal"; function create_fragment(ctx) { + let nested; let current; - const nested = new /*Nested*/ ctx[0]({ props: { foo: "bar" } }); + nested = new /*Nested*/ ctx[0]({ props: { foo: "bar" } }); return { c() { diff --git a/test/js/samples/component-static-var/expected.js b/test/js/samples/component-static-var/expected.js index 8a27ab6b24db..2cd5ed386f07 100644 --- a/test/js/samples/component-static-var/expected.js +++ b/test/js/samples/component-static-var/expected.js @@ -20,14 +20,16 @@ import Foo from "./Foo.svelte"; import Bar from "./Bar.svelte"; function create_fragment(ctx) { + let foo; let t0; + let bar; let t1; let input; let current; let mounted; let dispose; - const foo = new Foo({ props: { x: y } }); - const bar = new Bar({ props: { x: /*z*/ ctx[0] } }); + foo = new Foo({ props: { x: y } }); + bar = new Bar({ props: { x: /*z*/ ctx[0] } }); return { c() { diff --git a/test/js/samples/component-static/expected.js b/test/js/samples/component-static/expected.js index 26c63f550b65..186f6350e6bd 100644 --- a/test/js/samples/component-static/expected.js +++ b/test/js/samples/component-static/expected.js @@ -12,8 +12,9 @@ import { } from "svelte/internal"; function create_fragment(ctx) { + let nested; let current; - const nested = new /*Nested*/ ctx[0]({ props: { foo: "bar" } }); + nested = new /*Nested*/ ctx[0]({ props: { foo: "bar" } }); return { c() { diff --git a/test/js/samples/dynamic-import/expected.js b/test/js/samples/dynamic-import/expected.js index 4394e7d8a996..d1085f431b7c 100644 --- a/test/js/samples/dynamic-import/expected.js +++ b/test/js/samples/dynamic-import/expected.js @@ -14,8 +14,9 @@ import { import LazyLoad from "./LazyLoad.svelte"; function create_fragment(ctx) { + let lazyload; let current; - const lazyload = new LazyLoad({ props: { load: func } }); + lazyload = new LazyLoad({ props: { load: func } }); return { c() { diff --git a/test/js/samples/non-imported-component/expected.js b/test/js/samples/non-imported-component/expected.js index 2784fd17acb3..5a6b8e8bb730 100644 --- a/test/js/samples/non-imported-component/expected.js +++ b/test/js/samples/non-imported-component/expected.js @@ -17,10 +17,12 @@ import { import Imported from "Imported.svelte"; function create_fragment(ctx) { + let imported; let t; + let nonimported; let current; - const imported = new Imported({}); - const nonimported = new NonImported({}); + imported = new Imported({}); + nonimported = new NonImported({}); return { c() {