diff --git a/src/compiler/compile/render_dom/Renderer.ts b/src/compiler/compile/render_dom/Renderer.ts index c02d646ebf..5092626d25 100644 --- a/src/compiler/compile/render_dom/Renderer.ts +++ b/src/compiler/compile/render_dom/Renderer.ts @@ -60,7 +60,7 @@ export default class Renderer { if (component.slots.size > 0) { this.add_to_context('$$scope'); - this.add_to_context('$$slots'); + this.add_to_context('#slots'); } if (this.binding_groups.size > 0) { diff --git a/src/compiler/compile/render_dom/index.ts b/src/compiler/compile/render_dom/index.ts index 7d0dce8315..4ee9abae49 100644 --- a/src/compiler/compile/render_dom/index.ts +++ b/src/compiler/compile/render_dom/index.ts @@ -70,6 +70,15 @@ export default function dom( ); } + const uses_slots = component.var_lookup.has('$$slots'); + let compute_slots; + if (uses_slots) { + compute_slots = b` + const $$slots = @compute_slots(#slots); + `; + } + + const uses_props = component.var_lookup.has('$$props'); const uses_rest = component.var_lookup.has('$$restProps'); const $$props = uses_props || uses_rest ? `$$new_props` : `$$props`; @@ -409,13 +418,14 @@ export default function dom( ${resubscribable_reactive_store_unsubscribers} + ${component.slots.size || component.compile_options.dev || uses_slots ? b`let { $$slots: #slots = {}, $$scope } = $$props;` : null} + ${component.compile_options.dev && b`@validate_slots('${component.tag}', #slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`} + ${compute_slots} + ${instance_javascript} ${unknown_props_check} - ${component.slots.size || component.compile_options.dev ? b`let { $$slots = {}, $$scope } = $$props;` : null} - ${component.compile_options.dev && b`@validate_slots('${component.tag}', $$slots, [${[...component.slots.keys()].map(key => `'${key}'`).join(',')}]);`} - ${renderer.binding_groups.size > 0 && b`const $$binding_groups = [${[...renderer.binding_groups.keys()].map(_ => x`[]`)}];`} ${component.partly_hoisted} diff --git a/src/compiler/compile/render_dom/wrappers/Slot.ts b/src/compiler/compile/render_dom/wrappers/Slot.ts index bf808196c0..5c02e78158 100644 --- a/src/compiler/compile/render_dom/wrappers/Slot.ts +++ b/src/compiler/compile/render_dom/wrappers/Slot.ts @@ -125,7 +125,7 @@ export default class SlotWrapper extends Wrapper { const slot_or_fallback = has_fallback ? block.get_unique_name(`${sanitize(slot_name)}_slot_or_fallback`) : slot; block.chunks.init.push(b` - const ${slot_definition} = ${renderer.reference('$$slots')}.${slot_name}; + const ${slot_definition} = ${renderer.reference('#slots')}.${slot_name}; const ${slot} = @create_slot(${slot_definition}, #ctx, ${renderer.reference('$$scope')}, ${get_slot_context_fn}); ${has_fallback ? b`const ${slot_or_fallback} = ${slot} || ${this.fallback.name}(#ctx);` : null} `); diff --git a/src/compiler/compile/render_ssr/handlers/Slot.ts b/src/compiler/compile/render_ssr/handlers/Slot.ts index 3b1e199c75..32b6246e64 100644 --- a/src/compiler/compile/render_ssr/handlers/Slot.ts +++ b/src/compiler/compile/render_ssr/handlers/Slot.ts @@ -11,8 +11,8 @@ export default function(node: Slot, renderer: Renderer, options: RenderOptions) const result = renderer.pop(); renderer.add_expression(x` - $$slots.${node.slot_name} - ? $$slots.${node.slot_name}(${slot_data}) + #slots.${node.slot_name} + ? #slots.${node.slot_name}(${slot_data}) : ${result} `); } diff --git a/src/compiler/compile/render_ssr/index.ts b/src/compiler/compile/render_ssr/index.ts index a72b8b35ae..ff45abd78b 100644 --- a/src/compiler/compile/render_ssr/index.ts +++ b/src/compiler/compile/render_ssr/index.ts @@ -34,6 +34,9 @@ export default function ssr( const props = component.vars.filter(variable => !variable.module && variable.export_name); const rest = uses_rest ? b`let $$restProps = @compute_rest_props($$props, [${props.map(prop => `"${prop.export_name}"`).join(',')}]);` : null; + const uses_slots = component.var_lookup.has('$$slots'); + const slots = uses_slots ? b`let $$slots = @compute_slots(#slots);` : null; + const reactive_stores = component.vars.filter(variable => variable.name[0] === '$' && variable.name[1] !== '$'); const reactive_store_values = reactive_stores .map(({ name }) => { @@ -118,6 +121,7 @@ export default function ssr( const blocks = [ rest, + slots, ...reactive_stores.map(({ name }) => { const store_name = name.slice(1); const store = component.var_lookup.get(store_name); @@ -144,7 +148,7 @@ export default function ssr( ${component.fully_hoisted} - const ${name} = @create_ssr_component(($$result, $$props, $$bindings, $$slots) => { + const ${name} = @create_ssr_component(($$result, $$props, $$bindings, #slots) => { ${blocks} }); `; diff --git a/src/compiler/compile/utils/reserved_keywords.ts b/src/compiler/compile/utils/reserved_keywords.ts index 75825c1719..d6eb8b9673 100644 --- a/src/compiler/compile/utils/reserved_keywords.ts +++ b/src/compiler/compile/utils/reserved_keywords.ts @@ -1,4 +1,4 @@ -export const reserved_keywords = new Set(["$$props", "$$restProps"]); +export const reserved_keywords = new Set(["$$props", "$$restProps", "$$slots"]); export function is_reserved_keyword(name) { return reserved_keywords.has(name); diff --git a/src/runtime/internal/utils.ts b/src/runtime/internal/utils.ts index 3fd0a2b701..633b6f054c 100644 --- a/src/runtime/internal/utils.ts +++ b/src/runtime/internal/utils.ts @@ -128,6 +128,14 @@ export function compute_rest_props(props, keys) { return rest; } +export function compute_slots(slots) { + const result = {}; + for (const key in slots) { + result[key] = true; + } + return result; +} + export function once(fn) { let ran = false; return function(this: any, ...args) { diff --git a/test/runtime/samples/$$slot/A.svelte b/test/runtime/samples/$$slot/A.svelte new file mode 100644 index 0000000000..ffa166166c --- /dev/null +++ b/test/runtime/samples/$$slot/A.svelte @@ -0,0 +1,31 @@ + + + + + +$$slots: {toString($$slots)} + +{#if $$slots.b} +
+ +
+{:else} + Slot b is not available +{/if} \ No newline at end of file diff --git a/test/runtime/samples/$$slot/_config.js b/test/runtime/samples/$$slot/_config.js new file mode 100644 index 0000000000..13b2137cdb --- /dev/null +++ b/test/runtime/samples/$$slot/_config.js @@ -0,0 +1,18 @@ +export default { + html: ` + byeworld + hello world + $$slots: {"a":true,"default":true} + Slot b is not available + + bye world + hello world + $$slots: {"a":true,"b":true,"default":true} +
hello world
+ `, + + async test({ assert, target, component }) { + assert.equal(component.getA(), ''); + assert.equal(component.getB(), 'foo'); + } +}; diff --git a/test/runtime/samples/$$slot/main.svelte b/test/runtime/samples/$$slot/main.svelte new file mode 100644 index 0000000000..8b7efae573 --- /dev/null +++ b/test/runtime/samples/$$slot/main.svelte @@ -0,0 +1,23 @@ + + + + hello world + bye + world + + + + hello world + hello world + bye world +