mirror of
https://github.com/sveltejs/svelte.git
synced 2024-12-01 17:30:59 +01:00
Merge pull request #806 from sveltejs/gh-801
stack up append targets so that slotted content in nested components works in SSR mode
This commit is contained in:
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(
|
||||
|
15
src/generators/server-side-rendering/interfaces.ts
Normal file
15
src/generators/server-side-rendering/interfaces.ts
Normal file
@ -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…
Reference in New Issue
Block a user