Repository: sveltejs/svelte (JavaScript)
Date: 2017-09-10 17:13:11+00:00
Task type: Bug Fix

Issue:
If condition in default slot or try mount to empty fragment
First - example:
https://svelte.technology/repl?version=1.37.0&gist=77279f780755dcecd28eb8899a08e22d
and working one:
https://svelte.technology/repl?version=1.31.0&gist=77279f780755dcecd28eb8899a08e22d

it's happening because Svelte generates next code:
```js
if_block = create_if_block( state, component );
if_block.create();
if_block.mount( modal._slotted.default, null );
```

but modal._slotted.default it's just empty fragment because in the _fragment you did:
```js
if (slot_content_default) {
  appendNode(slot_content_default, div_1);
}
```
then slot_content_default it is our modal._slotted.default .

Anyway, we can't mount to slot we should find existent dom element for that. 
Example with cycle "each" don't work at all:
https://svelte.technology/repl?version=1.37.0&gist=70649b67d9f75bc91f3cc5c883b2c9e5


Issue discussion:
Wraparound - add root div element around all "slot" content. 
It will be like:
```js
if_block.mount( div, null );
```

Solution patch:
diff --git a/src/generators/dom/preprocess.ts b/src/generators/dom/preprocess.ts
--- a/src/generators/dom/preprocess.ts
+++ b/src/generators/dom/preprocess.ts
@@ -412,6 +412,8 @@ function preprocessChildren(
 	lastChild = null;
 
 	cleaned.forEach((child: Node, i: number) => {
+		child.parent = node;
+
 		const preprocessor = preprocessors[child.type];
 		if (preprocessor) preprocessor(generator, block, state, child, inEachBlock, elementStack, componentStack, stripWhitespace, cleaned[i + 1] || nextSibling);
 
diff --git a/src/generators/dom/visitors/EachBlock.ts b/src/generators/dom/visitors/EachBlock.ts
--- a/src/generators/dom/visitors/EachBlock.ts
+++ b/src/generators/dom/visitors/EachBlock.ts
@@ -21,7 +21,7 @@ export default function visitEachBlock(
 	const iterations = block.getUniqueName(`${each_block}_iterations`);
 	const params = block.params.join(', ');
 
-	const needsAnchor = node.next ? !isDomNode(node.next) : !state.parentNode;
+	const needsAnchor = node.next ? !isDomNode(node.next, generator) : !state.parentNode;
 	const anchor = needsAnchor
 		? block.getUniqueName(`${each_block}_anchor`)
 		: (node.next && node.next.var) || 'null';
diff --git a/src/generators/dom/visitors/IfBlock.ts b/src/generators/dom/visitors/IfBlock.ts
--- a/src/generators/dom/visitors/IfBlock.ts
+++ b/src/generators/dom/visitors/IfBlock.ts
@@ -80,7 +80,7 @@ export default function visitIfBlock(
 ) {
 	const name = node.var;
 
-	const needsAnchor = node.next ? !isDomNode(node.next) : !state.parentNode;
+	const needsAnchor = node.next ? !isDomNode(node.next, generator) : !state.parentNode || !isDomNode(node.parent, generator);
 	const anchor = needsAnchor
 		? block.getUniqueName(`${name}_anchor`)
 		: (node.next && node.next.var) || 'null';
@@ -94,7 +94,7 @@ export default function visitIfBlock(
 	const dynamic = branches[0].hasUpdateMethod; // can use [0] as proxy for all, since they necessarily have the same value
 	const hasOutros = branches[0].hasOutroMethod;
 
-	const vars = { name, anchor, params, if_name, hasElse };
+	const vars = { name, needsAnchor, anchor, params, if_name, hasElse };
 
 	if (node.else) {
 		if (hasOutros) {
@@ -137,7 +137,7 @@ function simple(
 	node: Node,
 	branch,
 	dynamic,
-	{ name, anchor, params, if_name }
+	{ name, needsAnchor, anchor, params, if_name }
 ) {
 	block.builders.init.addBlock(deindent`
 		var ${name} = (${branch.condition}) && ${branch.block}(${params}, #component);
@@ -152,7 +152,7 @@ function simple(
 		`if (${name}) ${name}.${mountOrIntro}(${targetNode}, ${anchorNode});`
 	);
 
-	const parentNode = state.parentNode || `${anchor}.parentNode`;
+	const parentNode = (state.parentNode && !needsAnchor) ? state.parentNode : `${anchor}.parentNode`;
 
 	const enter = dynamic
 		? branch.hasIntroMethod
@@ -227,7 +227,7 @@ function compound(
 	node: Node,
 	branches,
 	dynamic,
-	{ name, anchor, params, hasElse, if_name }
+	{ name, needsAnchor, anchor, params, hasElse, if_name }
 ) {
 	const select_block_type = generator.getUniqueName(`select_block_type`);
 	const current_block_type = block.getUniqueName(`current_block_type`);
@@ -255,7 +255,7 @@ function compound(
 		`${if_name}${name}.${mountOrIntro}(${targetNode}, ${anchorNode});`
 	);
 
-	const parentNode = state.parentNode || `${anchor}.parentNode`;
+	const parentNode = (state.parentNode && !needsAnchor) ? state.parentNode : `${anchor}.parentNode`;
 
 	const changeBlock = deindent`
 		${hasElse
@@ -303,7 +303,7 @@ function compoundWithOutros(
 	node: Node,
 	branches,
 	dynamic,
-	{ name, anchor, params, hasElse }
+	{ name, needsAnchor, anchor, params, hasElse }
 ) {
 	const select_block_type = block.getUniqueName(`select_block_type`);
 	const current_block_type_index = block.getUniqueName(`current_block_type_index`);
@@ -354,7 +354,7 @@ function compoundWithOutros(
 		`${if_current_block_type_index}${if_blocks}[${current_block_type_index}].${mountOrIntro}(${targetNode}, ${anchorNode});`
 	);
 
-	const parentNode = state.parentNode || `${anchor}.parentNode`;
+	const parentNode = (state.parentNode && !needsAnchor) ? state.parentNode : `${anchor}.parentNode`;
 
 	const destroyOldBlock = deindent`
 		${name}.outro(function() {
diff --git a/src/generators/dom/visitors/shared/isDomNode.ts b/src/generators/dom/visitors/shared/isDomNode.ts
--- a/src/generators/dom/visitors/shared/isDomNode.ts
+++ b/src/generators/dom/visitors/shared/isDomNode.ts
@@ -1,5 +1,7 @@
+import { DomGenerator } from '../../index';
 import { Node } from '../../../../interfaces';
 
-export default function isDomNode(node: Node) {
-	return node.type === 'Element' || node.type === 'Text' || node.type === 'MustacheTag';
+export default function isDomNode(node: Node, generator: DomGenerator) {
+	if (node.type === 'Element') return !generator.components.has(node.name);
+	return node.type === 'Text' || node.type === 'MustacheTag';
 }
\ No newline at end of file


Test patch:
diff --git a/test/runtime/samples/component-slot-if-block/Nested.html b/test/runtime/samples/component-slot-if-block/Nested.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-slot-if-block/Nested.html
@@ -0,0 +1,3 @@
+<div>
+	<slot/>
+</div>
\ No newline at end of file
diff --git a/test/runtime/samples/component-slot-if-block/_config.js b/test/runtime/samples/component-slot-if-block/_config.js
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-slot-if-block/_config.js
@@ -0,0 +1,16 @@
+export default {
+	html: `
+		<div>
+			<p>unconditional</p>
+		</div>`,
+
+	test(assert, component, target) {
+		component.set({ foo: true });
+		assert.htmlEqual(target.innerHTML, `
+			<div>
+				<p>unconditional</p>
+				<p>conditional</p>
+			</div>
+		`);
+	}
+};
diff --git a/test/runtime/samples/component-slot-if-block/main.html b/test/runtime/samples/component-slot-if-block/main.html
new file mode 100644
--- /dev/null
+++ b/test/runtime/samples/component-slot-if-block/main.html
@@ -0,0 +1,17 @@
+<Nested>
+	<p>unconditional</p>
+
+	{{#if foo}}
+		<p>conditional</p>
+	{{/if}}
+</Nested>
+
+<script>
+	import Nested from './Nested.html';
+
+	export default {
+		components: {
+			Nested
+		}
+	};
+</script>
\ No newline at end of file