Repository: sveltejs/svelte (JavaScript)
Date: 2020-05-03 13:08:04+00:00
Task type: Bug Fix

Issue:
when component name is Anchor, it'll break the app
**Describe the bug**

when doing `import Anchor from './Anchor.svelte` and use it, it'll break the app and showing `component is undefined`. After changing name to anything else it works.

**To Reproduce**

[repl](https://svelte.dev/repl/164f2abd2ca044b1b21652f3083589a0?version=3.21.0)

1. open REPL
2. You'll see error message `component is undefined` in console
3. uncomment `HappyAnchor` and comment `Anchor`, it works now!

**Expected behavior**

I've tried to read documentation and tutorial to see if there is some reserved word that I can not use as component name, but I couldn't find it. So I think we should allow `Anchor` as component name?

**Information about your Svelte project:**
- In Chrome 81, it shows `Cannot read property '$$' of undefined`
- In Firefox 75, it shows `component is undefined`
- svelte version: 3.21.0



Issue discussion:

Solution patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 * Do not display a11y warning about missing `href` for `<a>` with `name` or `id` ([#4697](https://github.com/sveltejs/svelte/issues/4697))
 * Disable infinite loop guard inside generators ([#4698](https://github.com/sveltejs/svelte/issues/4698))
 * Display a11y warning for `href="javascript:..."` ([#4733](https://github.com/sveltejs/svelte/pull/4733))
+* Fix variable name conflict with component called `<Anchor>` ([#4768](https://github.com/sveltejs/svelte/issues/4768))
 
 ## 3.21.0
 
diff --git a/src/compiler/compile/render_dom/Block.ts b/src/compiler/compile/render_dom/Block.ts
--- a/src/compiler/compile/render_dom/Block.ts
+++ b/src/compiler/compile/render_dom/Block.ts
@@ -185,7 +185,7 @@ export default class Block {
 			this.chunks.mount.push(b`@append(${parent_node}, ${id});`);
 			if (is_head(parent_node) && !no_detach) this.chunks.destroy.push(b`@detach(${id});`);
 		} else {
-			this.chunks.mount.push(b`@insert(#target, ${id}, anchor);`);
+			this.chunks.mount.push(b`@insert(#target, ${id}, #anchor);`);
 			if (!no_detach) this.chunks.destroy.push(b`if (detaching) @detach(${id});`);
 		}
 	}
@@ -295,11 +295,11 @@ export default class Block {
 		if (this.chunks.mount.length === 0) {
 			properties.mount = noop;
 		} else if (this.event_listeners.length === 0) {
-			properties.mount = x`function #mount(#target, anchor) {
+			properties.mount = x`function #mount(#target, #anchor) {
 				${this.chunks.mount}
 			}`;
 		} else {
-			properties.mount = x`function #mount(#target, anchor, #remount) {
+			properties.mount = x`function #mount(#target, #anchor, #remount) {
 				${this.chunks.mount}
 			}`;
 		}
diff --git a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts
--- a/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts
+++ b/src/compiler/compile/render_dom/wrappers/AwaitBlock.ts
@@ -200,7 +200,7 @@ export default class AwaitBlockWrapper extends Wrapper {
 		}
 
 		const initial_mount_node = parent_node || '#target';
-		const anchor_node = parent_node ? 'null' : 'anchor';
+		const anchor_node = parent_node ? 'null' : '#anchor';
 
 		const has_transitions = this.pending.block.has_intro_method || this.pending.block.has_outro_method;
 
diff --git a/src/compiler/compile/render_dom/wrappers/EachBlock.ts b/src/compiler/compile/render_dom/wrappers/EachBlock.ts
--- a/src/compiler/compile/render_dom/wrappers/EachBlock.ts
+++ b/src/compiler/compile/render_dom/wrappers/EachBlock.ts
@@ -219,7 +219,7 @@ export default class EachBlockWrapper extends Wrapper {
 			}
 		`);
 
-		const initial_anchor_node: Identifier = { type: 'Identifier', name: parent_node ? 'null' : 'anchor' };
+		const initial_anchor_node: Identifier = { type: 'Identifier', name: parent_node ? 'null' : '#anchor' };
 		const initial_mount_node: Identifier = parent_node || { type: 'Identifier', name: '#target' };
 		const update_anchor_node = needs_anchor
 			? block.get_unique_name(`${this.var.name}_anchor`)
diff --git a/src/compiler/compile/render_dom/wrappers/Element/index.ts b/src/compiler/compile/render_dom/wrappers/Element/index.ts
--- a/src/compiler/compile/render_dom/wrappers/Element/index.ts
+++ b/src/compiler/compile/render_dom/wrappers/Element/index.ts
@@ -320,7 +320,7 @@ export default class ElementWrapper extends Wrapper {
 				block.chunks.destroy.push(b`@detach(${node});`);
 			}
 		} else {
-			block.chunks.mount.push(b`@insert(#target, ${node}, anchor);`);
+			block.chunks.mount.push(b`@insert(#target, ${node}, #anchor);`);
 
 			// TODO we eventually need to consider what happens to elements
 			// that belong to the same outgroup as an outroing element...
diff --git a/src/compiler/compile/render_dom/wrappers/IfBlock.ts b/src/compiler/compile/render_dom/wrappers/IfBlock.ts
--- a/src/compiler/compile/render_dom/wrappers/IfBlock.ts
+++ b/src/compiler/compile/render_dom/wrappers/IfBlock.ts
@@ -293,7 +293,7 @@ export default class IfBlockWrapper extends Wrapper {
 		`);
 
 		const initial_mount_node = parent_node || '#target';
-		const anchor_node = parent_node ? 'null' : 'anchor';
+		const anchor_node = parent_node ? 'null' : '#anchor';
 
 		if (if_exists_condition) {
 			block.chunks.mount.push(
@@ -423,7 +423,7 @@ export default class IfBlockWrapper extends Wrapper {
 		}
 
 		const initial_mount_node = parent_node || '#target';
-		const anchor_node = parent_node ? 'null' : 'anchor';
+		const anchor_node = parent_node ? 'null' : '#anchor';
 
 		block.chunks.mount.push(
 			if_current_block_type_index(
@@ -519,7 +519,7 @@ export default class IfBlockWrapper extends Wrapper {
 		`);
 
 		const initial_mount_node = parent_node || '#target';
-		const anchor_node = parent_node ? 'null' : 'anchor';
+		const anchor_node = parent_node ? 'null' : '#anchor';
 
 		block.chunks.mount.push(
 			b`if (${name}) ${name}.m(${initial_mount_node}, ${anchor_node});`
diff --git a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
--- a/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
+++ b/src/compiler/compile/render_dom/wrappers/InlineComponent/index.ts
@@ -435,7 +435,7 @@ export default class InlineComponentWrapper extends Wrapper {
 
 			block.chunks.mount.push(b`
 				if (${name}) {
-					@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});
+					@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});
 				}
 			`);
 
@@ -509,7 +509,7 @@ export default class InlineComponentWrapper extends Wrapper {
 			}
 
 			block.chunks.mount.push(
-				b`@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});`
+				b`@mount_component(${name}, ${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});`
 			);
 
 			block.chunks.intro.push(b`
diff --git a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts
--- a/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts
+++ b/src/compiler/compile/render_dom/wrappers/RawMustacheTag.ts
@@ -54,7 +54,7 @@ export default class RawMustacheTagWrapper extends Tag {
 			const update_anchor = in_head ? 'null' : needs_anchor ? html_anchor : this.next ? this.next.var : 'null';
 
 			block.chunks.hydrate.push(b`${html_tag} = new @HtmlTag(${init}, ${update_anchor});`);
-			block.chunks.mount.push(b`${html_tag}.m(${parent_node || '#target'}, ${parent_node ? null : 'anchor'});`);
+			block.chunks.mount.push(b`${html_tag}.m(${parent_node || '#target'}, ${parent_node ? null : '#anchor'});`);
 
 			if (needs_anchor) {
 				block.add_element(html_anchor, x`@empty()`, x`@empty()`, parent_node);
diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts
--- a/src/compiler/compile/render_dom/wrappers/Slot.ts
+++ b/src/compiler/compile/render_dom/wrappers/Slot.ts
@@ -145,7 +145,7 @@ export default class SlotWrapper extends Wrapper {
 
 		block.chunks.mount.push(b`
 			if (${slot_or_fallback}) {
-				${slot_or_fallback}.m(${parent_node || '#target'}, ${parent_node ? 'null' : 'anchor'});
+				${slot_or_fallback}.m(${parent_node || '#target'}, ${parent_node ? 'null' : '#anchor'});
 			}
 		`);
 


Test patch:
diff --git a/test/runtime/samples/deconflict-anchor/Anchor.svelte b/test/runtime/samples/deconflict-anchor/Anchor.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/deconflict-anchor/Anchor.svelte
@@ -0,0 +1 @@
+<p>Anchor</p>
diff --git a/test/runtime/samples/deconflict-anchor/_config.js b/test/runtime/samples/deconflict-anchor/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/deconflict-anchor/_config.js
@@ -0,0 +1,4 @@
+export default {
+	preserveIdentifiers: true,
+	html: `<p>Anchor</p>`
+};
diff --git a/test/runtime/samples/deconflict-anchor/main.svelte b/test/runtime/samples/deconflict-anchor/main.svelte
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/deconflict-anchor/main.svelte
@@ -0,0 +1,5 @@
+<script>
+	import Anchor from './Anchor.svelte';
+</script>
+
+<Anchor/>