diff --git a/.changeset/brown-boats-nail.md b/.changeset/brown-boats-nail.md new file mode 100644 index 00000000..0c413937 --- /dev/null +++ b/.changeset/brown-boats-nail.md @@ -0,0 +1,5 @@ +--- +'preact-render-to-string': patch +--- + +Fix `preact/debug` incorrectly throwing errors on text children diff --git a/src/index.js b/src/index.js index bd596ba9..9d816d6d 100644 --- a/src/index.js +++ b/src/index.js @@ -165,6 +165,23 @@ function renderClassComponent(vnode, context) { return c.render(c.props, c.state, c.context); } +/** + * @param {any} vnode + * @returns {VNode} + */ +function normalizeVNode(vnode) { + if (vnode == null || typeof vnode == 'boolean') { + return null; + } else if ( + typeof vnode == 'string' || + typeof vnode == 'number' || + typeof vnode == 'bigint' + ) { + return h(null, null, vnode); + } + return vnode; +} + /** * @param {string} name * @param {boolean} isSvgMode @@ -237,6 +254,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) { rendered = rendered + _renderToString(vnode[i], context, isSvgMode, selectValue, parent); + + vnode[i] = normalizeVNode(vnode[i]); } return rendered; } @@ -372,6 +391,8 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) { vnode[CHILDREN] = children; for (let i = 0; i < children.length; i++) { let child = children[i]; + children[i] = normalizeVNode(child); + if (child != null && child !== false) { let childSvgMode = type === 'svg' || (type !== 'foreignObject' && isSvgMode); @@ -391,7 +412,7 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) { } } } else if (children != null && children !== false && children !== true) { - vnode[CHILDREN] = [children]; + vnode[CHILDREN] = [normalizeVNode(children)]; let childSvgMode = type === 'svg' || (type !== 'foreignObject' && isSvgMode); let ret = _renderToString( diff --git a/test/debug.test.js b/test/debug.test.js new file mode 100644 index 00000000..d794a8ea --- /dev/null +++ b/test/debug.test.js @@ -0,0 +1,26 @@ +import 'preact/debug'; +import { render } from '../src'; +import { h } from 'preact'; +import { expect } from 'chai'; + +describe('debug', () => { + it('should not throw "Objects are not valid as a child" error', () => { + expect(() => render(
{'foo'}
)).not.to.throw(); + expect(() => render({2}
)).not.to.throw(); + expect(() => render({true}
)).not.to.throw(); + expect(() => render({false}
)).not.to.throw(); + expect(() => render({null}
)).not.to.throw(); + expect(() => render({undefined}
)).not.to.throw(); + }); + + it('should not throw "Objects are not valid as a child" error #2', () => { + function Str() { + return ['foo']; + } + expect(() => render({'foo'}bar
)).not.to.throw(); + }); +});