Merge pull request #806 from sveltejs/gh-801

stack up append targets so that slotted content in nested components works in SSR mode
pull/807/head
Rich Harris 7 years ago committed by GitHub
commit 865e84b856

@ -6,13 +6,13 @@ import preprocess from './preprocess';
import visit from './visit';
import { removeNode, removeObjectKey } from '../../utils/removeNode';
import { Parsed, Node, CompileOptions } from '../../interfaces';
import { AppendTarget } from './interfaces';
import { stringify } from '../../utils/stringify';
export class SsrGenerator extends Generator {
bindings: string[];
renderCode: string;
appendTargets: Record<string, string> | null;
appendTarget: string | null;
appendTargets: AppendTarget[];
constructor(
parsed: Parsed,
@ -24,7 +24,7 @@ export class SsrGenerator extends Generator {
super(parsed, source, name, stylesheet, options);
this.bindings = [];
this.renderCode = '';
this.appendTargets = null;
this.appendTargets = [];
// in an SSR context, we don't need to include events, methods, oncreate or ondestroy
const { templateProperties, defaultExport } = this;
@ -60,24 +60,14 @@ export class SsrGenerator extends Generator {
}
append(code: string) {
if (this.appendTarget) {
this.appendTargets[this.appendTarget] += code;
if (this.appendTargets.length) {
const appendTarget = this.appendTargets[this.appendTargets.length - 1];
const slotName = appendTarget.slotStack[appendTarget.slotStack.length - 1];
appendTarget.slots[slotName] += code;
} else {
this.renderCode += code;
}
}
removeAppendTarget() {
this.appendTarget = this.appendTargets = null;
}
setAppendTarget(name: string) {
if (!this.appendTargets[name]) {
this.appendTargets[name] = '';
}
this.appendTarget = name;
}
}
export default function ssr(

@ -0,0 +1,15 @@
import { SsrGenerator } from './index';
import Block from './Block';
import { Node } from '../../interfaces';
export type Visitor = (
generator: SsrGenerator,
block: Block,
node: Node,
componentStack: Node[]
) => void;
export interface AppendTarget {
slots: Record<string, string>;
slotStack: string[]
}

@ -2,6 +2,7 @@ import flattenReference from '../../../utils/flattenReference';
import visit from '../visit';
import { SsrGenerator } from '../index';
import Block from '../Block';
import { AppendTarget } from '../interfaces';
import { Node } from '../../../interfaces';
import getObject from '../../../utils/getObject';
import getTailSnippet from '../../../utils/getTailSnippet';
@ -80,19 +81,24 @@ export default function visitComponent(
let open = `\${${expression}.render({${props}}`;
if (node.children.length) {
generator.appendTargets = {};
generator.setAppendTarget('default');
const appendTarget: AppendTarget = {
slots: { default: '' },
slotStack: ['default']
};
generator.appendTargets.push(appendTarget);
node.children.forEach((child: Node) => {
visit(generator, block, child);
});
const slotted = Object.keys(generator.appendTargets)
.map(name => `${name}: () => \`${generator.appendTargets[name]}\``)
const slotted = Object.keys(appendTarget.slots)
.map(name => `${name}: () => \`${appendTarget.slots[name]}\``)
.join(', ');
open += `, { slotted: { ${slotted} } }`;
generator.setAppendTarget(null);
generator.appendTargets.pop();
}
generator.append(open);

@ -49,7 +49,10 @@ export default function visitElement(
const slot = node.attributes.find((attribute: Node) => attribute.name === 'slot');
if (slot) {
generator.setAppendTarget(slot.value[0].data);
const slotName = slot.value[0].data;
const appendTarget = generator.appendTargets[generator.appendTargets.length - 1];
appendTarget.slotStack.push(slotName);
appendTarget.slots[slotName] = '';
}
node.attributes.forEach((attribute: Node) => {

@ -0,0 +1,3 @@
<div class='inner'>
<slot></slot>
</div>

@ -0,0 +1,3 @@
<div class='outer'>
<slot></slot>
</div>

@ -0,0 +1,6 @@
export default {
html: `
<div class='outer'>
<div class='inner'>foo</div>
</div>`
};

@ -0,0 +1,12 @@
<Outer>
<Inner>foo</Inner>
</Outer>
<script>
import Outer from './Outer.html';
import Inner from './Inner.html';
export default {
components: { Outer, Inner }
};
</script>
Loading…
Cancel
Save