Skip to content

Commit

Permalink
Support array and fragment during SSR (#1503)
Browse files Browse the repository at this point in the history
* Added tests for rendering array and fragment

* Fix SSR rendering of arrays

* Added tests for rendering array and fragment for streaming renderer

* Fix SSR rendering of arrays and fragments for streaming renderer

* Added tests for rendering array and fragment for queue-streaming renderer

* Fix SSR rendering of arrays and fragments for queue-streaming renderer

* Changed var name to fix tslint-error "Shadowed name: 'children'"
  • Loading branch information
jhsware authored and Havunen committed Jan 28, 2020
1 parent 888b0c7 commit 9396ade
Show file tree
Hide file tree
Showing 6 changed files with 156 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,43 @@ describe('SSR Creation Queue Streams - (non-JSX)', () => {
</div>
),
result: '<div><br></div>'
},
{
description: 'You should be able to render an array',
template: () => (
[
<p>1</p>,
<p>2</p>,
<p>3</p>
]
),
result: '<p>1</p><p>2</p><p>3</p>'
},
{
description: 'You should be able to render an empty array',
template: () => [],
result: '<!--!-->'
},
{
description: 'You should be able to render a fragment',
template: () => (
<>
<p>1</p>
<p>2</p>
<p>3</p>
</> /* reset syntax highlighting */
),
result: '<p>1</p><p>2</p><p>3</p>'
},
{
description: 'You should be able to render an empty fragment',
template: () => (<></>), /* reset syntax highlighting */
result: '<!--!-->'
},
{
description: 'You should be able to render fragment with single child',
template: () => (<><p>1</p></>), /* reset syntax highlighting */
result: '<p>1</p>'
}
];

Expand Down
37 changes: 37 additions & 0 deletions packages/inferno-server/__tests__/creation-stream.spec.server.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,43 @@ describe('SSR Creation Streams - (non-JSX)', () => {
</div>
),
result: '<div><br></div>'
},
{
description: 'You should be able to render an array',
template: () => (
[
<p>1</p>,
<p>2</p>,
<p>3</p>
]
),
result: '<p>1</p><p>2</p><p>3</p>'
},
{
description: 'You should be able to render an empty array',
template: () => [],
result: '<!--!-->'
},
{
description: 'You should be able to render a fragment',
template: () => (
<>
<p>1</p>
<p>2</p>
<p>3</p>
</> /* reset syntax highlighting */
),
result: '<p>1</p><p>2</p><p>3</p>'
},
{
description: 'You should be able to render an empty fragment',
template: () => (<></>), /* reset syntax highlighting */
result: '<!--!-->'
},
{
description: 'You should be able to render fragment with single child',
template: () => (<><p>1</p></>), /* reset syntax highlighting */
result: '<p>1</p>'
}
];

Expand Down
37 changes: 37 additions & 0 deletions packages/inferno-server/__tests__/creation.spec.server.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,43 @@ describe('SSR Creation (JSX)', () => {
</div>
),
result: '<div><br></div>'
},
{
description: 'You should be able to render an array',
template: () => (
[
<p>1</p>,
<p>2</p>,
<p>3</p>
]
),
result: '<p>1</p><p>2</p><p>3</p>'
},
{
description: 'You should be able to render an empty array',
template: () => [],
result: '<!--!-->'
},
{
description: 'You should be able to render a fragment',
template: () => (
<>
<p>1</p>
<p>2</p>
<p>3</p>
</> /* reset syntax highlighting */
),
result: '<p>1</p><p>2</p><p>3</p>'
},
{
description: 'You should be able to render an empty fragment',
template: () => (<></>), /* reset syntax highlighting */
result: '<!--!-->'
},
{
description: 'You should be able to render fragment with single child',
template: () => (<><p>1</p></>), /* reset syntax highlighting */
result: '<p>1</p>'
}
];

Expand Down
15 changes: 15 additions & 0 deletions packages/inferno-server/src/renderToString.queuestream.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {EMPTY_OBJ} from 'inferno';
import {
combineFrom,
isArray,
isFunction,
isInvalid,
isNull,
Expand Down Expand Up @@ -281,6 +282,20 @@ export class RenderQueueStream extends Readable {
// Push text directly to queue
} else if ((flags & VNodeFlags.Text) > 0) {
this.addToQueue(children === '' ? ' ' : escapeText(children), position);
// Handle fragments and arrays
} else if (isArray(vNode) || (flags & VNodeFlags.Fragment) !== 0) {
const childFlags = vNode.childFlags;

if (childFlags === ChildFlags.HasVNodeChildren || (isArray(vNode) && vNode.length === 0)) {
this.addToQueue ('<!--!-->', position);
} else if (childFlags & ChildFlags.MultipleChildren || isArray(vNode)) {
const tmpChildren = isArray(vNode) ? vNode : vNode.children;

for (let i = 0, len = tmpChildren.length; i < len; ++i) {
this.renderVNodeToQueue(tmpChildren[i], context, position);
}
return;
}
// Handle errors
} else {
if (process.env.NODE_ENV !== 'production') {
Expand Down
22 changes: 21 additions & 1 deletion packages/inferno-server/src/renderToString.stream.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {combineFrom, isFunction, isInvalid, isNull, isNullOrUndef, isNumber, isString} from 'inferno-shared';
import {combineFrom, isArray, isFunction, isInvalid, isNull, isNullOrUndef, isNumber, isString} from 'inferno-shared';
import {ChildFlags, VNodeFlags} from 'inferno-vnode-flags';
import {Readable} from 'stream';
import {renderStylesToString} from './prop-renderers';
Expand Down Expand Up @@ -43,10 +43,30 @@ export class RenderStream extends Readable {
if ((flags & VNodeFlags.Element) > 0) {
return this.renderElement(vNode, context);
}
if (isArray(vNode) || (flags & VNodeFlags.Fragment) !== 0) {
return this.renderArrayOrFragment(vNode, context)
}


return this.renderText(vNode);
}

public renderArrayOrFragment(vNode, context) {
const childFlags = vNode.childFlags;

if (childFlags === ChildFlags.HasVNodeChildren || (isArray(vNode) && vNode.length === 0)) {
return this.push('<!--!-->');
} else if (childFlags & ChildFlags.MultipleChildren || isArray(vNode)) {
const children = isArray(vNode) ? vNode : vNode.children;

return (children as VNode[]).reduce((p, child) => {
return p.then(() => {
return Promise.resolve(this.renderNode(child, context)).then(() => !!(child.flags & VNodeFlags.Text));
});
}, Promise.resolve(false));
}
}

public renderComponent(vComponent, context, isClass) {
const type = vComponent.type;
const props = vComponent.props;
Expand Down
16 changes: 9 additions & 7 deletions packages/inferno-server/src/renderToString.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {EMPTY_OBJ} from 'inferno';
import {
combineFrom,
isArray,
isFunction,
isInvalid,
isNull,
Expand Down Expand Up @@ -180,16 +181,17 @@ function renderVNodeToString(vNode, parent, context): string {
return renderedString;
} else if ((flags & VNodeFlags.Text) !== 0) {
return children === '' ? ' ' : escapeText(children);
} else if ((flags & VNodeFlags.Fragment) !== 0) {
} else if (isArray(vNode) || (flags & VNodeFlags.Fragment) !== 0) {
const childFlags = vNode.childFlags;

if (childFlags === ChildFlags.HasVNodeChildren) {
if (childFlags === ChildFlags.HasVNodeChildren || (isArray(vNode) && vNode.length === 0)) {
return '<!--!-->';
} else if (childFlags & ChildFlags.MultipleChildren) {
} else if (childFlags & ChildFlags.MultipleChildren || isArray(vNode)) {
const tmpNodes = isArray(vNode) ? vNode : children;
let renderedString = '';

for (let i = 0, len = children.length; i < len; ++i) {
renderedString += renderVNodeToString(children[i], vNode, context);
for (let i = 0, len = tmpNodes.length; i < len; ++i) {
renderedString += renderVNodeToString(tmpNodes[i], vNode, context);
}

return renderedString;
Expand Down

0 comments on commit 9396ade

Please sign in to comment.