diff --git a/.changeset/dull-jobs-sin.md b/.changeset/dull-jobs-sin.md new file mode 100644 index 00000000..6d2c6bfd --- /dev/null +++ b/.changeset/dull-jobs-sin.md @@ -0,0 +1,14 @@ +--- +'preact-render-to-string': minor +--- + +Add support for precompiled JSX transform, see https://deno.com/blog/v1.38#fastest-jsx-transform. Compared to traditional JSX transforms, the precompiled JSX transform tries to pre-serialize as much of the JSX as possible. That way less objects need to be created and serialized which relieves a lot of GC pressure. + +```jsx +// input +
hello
; + +// output +const tpl = [`
hello
`]; +jsxTemplate(tpl); +``` diff --git a/src/index.js b/src/index.js index 4ceda2a0..8b294e06 100644 --- a/src/index.js +++ b/src/index.js @@ -182,9 +182,36 @@ function _renderToString(vnode, context, isSvgMode, selectValue, parent) { // Invoke rendering on Components if (typeof type === 'function') { if (type === Fragment) { - // Fragments are the least used components of core that's why - // branching here for comments has the least effect on perf. - if (props.UNSTABLE_comment) { + // Serialized precompiled JSX. + if (props.tpl) { + let out = ''; + for (let i = 0; i < props.tpl.length; i++) { + out += props.tpl[i]; + + if (props.exprs && i < props.exprs.length) { + const value = props.exprs[i]; + if (value == null) continue; + + // Check if we're dealing with a vnode + if (typeof value === 'object' && value.constructor === undefined) { + out += _renderToString( + value, + context, + isSvgMode, + selectValue, + vnode + ); + } else { + // Values are pre-escaped by the JSX transform + out += props.exprs[i]; + } + } + } + + return out; + } else if (props.UNSTABLE_comment) { + // Fragments are the least used components of core that's why + // branching here for comments has the least effect on perf. return ''; } diff --git a/test/render.test.js b/test/render.test.js index f8060d80..d84f024f 100644 --- a/test/render.test.js +++ b/test/render.test.js @@ -1650,4 +1650,28 @@ describe('render', () => { } }); }); + + describe('precompiled JSX', () => { + it('should render template', () => { + let vnode = foo']} exprs={[]} />; + let rendered = render(vnode); + expect(rendered).to.equal('
foo
'); + }); + + it('should render template with attribute expressions', () => { + let vnode = ( + foo']} exprs={['class="foo"']} /> + ); + let rendered = render(vnode); + expect(rendered).to.equal('
foo
'); + }); + + it('should render template with child expressions', () => { + let vnode = ( + foo', '']} exprs={[bar]} /> + ); + let rendered = render(vnode); + expect(rendered).to.equal('
foobar
'); + }); + }); });