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
');
+ });
+ });
});