diff --git a/.changeset/orange-beds-pay.md b/.changeset/orange-beds-pay.md new file mode 100644 index 00000000..3c193ec5 --- /dev/null +++ b/.changeset/orange-beds-pay.md @@ -0,0 +1,5 @@ +--- +'preact-render-to-string': major +--- + +stream Suspense chunks via declarative shadow dom diff --git a/src/lib/chunked.js b/src/lib/chunked.js index cd1686d1..9a932e18 100644 --- a/src/lib/chunked.js +++ b/src/lib/chunked.js @@ -1,7 +1,15 @@ import { renderToString } from '../index.js'; import { CHILD_DID_SUSPEND, COMPONENT, PARENT } from './constants.js'; import { Deferred } from './util.js'; -import { createInitScript, createSubtree } from './client.js'; + +/** + * @param {string} id + * @param {string} content + * @returns {string} + */ +export function createSubtree(id, content) { + return ``; +} /** * @param {VNode} vnode @@ -28,11 +36,8 @@ export async function renderToChunks(vnode, { context, onWrite, abortSignal }) { // Wait for any suspended sub-trees if there are any const len = renderer.suspended.length; if (len > 0) { - onWrite(''); } } @@ -93,5 +98,5 @@ function handleError(error, vnode, renderChild) { return found ? '' - : `${fallback}`; + : ``; } diff --git a/src/lib/client.js b/src/lib/client.js deleted file mode 100644 index c0f5cb72..00000000 --- a/src/lib/client.js +++ /dev/null @@ -1,62 +0,0 @@ -/* eslint-disable no-var, key-spacing, object-curly-spacing, prefer-arrow-callback, semi, keyword-spacing */ - -// function initPreactIslandElement() { -// class PreactIslandElement extends HTMLElement { -// connectedCallback() { -// var d = this; -// if (!d.isConnected) return; - -// let i = this.getAttribute('data-target'); -// if (!i) return; - -// var s, -// e, -// c = document.createNodeIterator(document, 128); -// while (c.nextNode()) { -// let n = c.referenceNode; - -// if (n.data == 'preact-island:' + i) s = n; -// else if (n.data == '/preact-island:' + i) e = n; -// if (s && e) break; -// } -// if (s && e) { -// requestAnimationFrame(() => { -// var p = e.previousSibling; -// while (p != s) { -// if (!p || p == s) break; -// e.parentNode.removeChild(p); -// p = e.previousSibling; -// } - -// c = s; -// while (d.firstChild) { -// s = d.firstChild; -// d.removeChild(s); -// c.after(s); -// c = s; -// } - -// d.parentNode.removeChild(d); -// }); -// } -// } -// } - -// customElements.define('preact-island', PreactIslandElement); -// } - -// To modify the INIT_SCRIPT, uncomment the above code, modify it, and paste it into https://try.terser.org/. -const INIT_SCRIPT = `class e extends HTMLElement{connectedCallback(){var e=this;if(!e.isConnected)return;let t=this.getAttribute("data-target");if(t){for(var r,a,i=document.createNodeIterator(document,128);i.nextNode();){let e=i.referenceNode;if(e.data=="preact-island:"+t?r=e:e.data=="/preact-island:"+t&&(a=e),r&&a)break}r&&a&&requestAnimationFrame((()=>{for(var t=a.previousSibling;t!=r&&t&&t!=r;)a.parentNode.removeChild(t),t=a.previousSibling;for(i=r;e.firstChild;)r=e.firstChild,e.removeChild(r),i.after(r),i=r;e.parentNode.removeChild(e)}))}}}customElements.define("preact-island",e);`; - -export function createInitScript() { - return ``; -} - -/** - * @param {string} id - * @param {string} content - * @returns {string} - */ -export function createSubtree(id, content) { - return ``; -} diff --git a/src/lib/util.js b/src/lib/util.js index 4be4e192..7487bfcd 100644 --- a/src/lib/util.js +++ b/src/lib/util.js @@ -1,4 +1,4 @@ -import { DIRTY, BITS } from './constants'; +import { DIRTY, BITS } from './constants.js'; export const VOID_ELEMENTS = /^(?:area|base|br|col|embed|hr|img|input|link|meta|param|source|track|wbr)$/; // oxlint-disable-next-line no-control-regex diff --git a/test/compat/render-chunked.test.jsx b/test/compat/render-chunked.test.jsx index 3f20e517..5381273c 100644 --- a/test/compat/render-chunked.test.jsx +++ b/test/compat/render-chunked.test.jsx @@ -2,8 +2,7 @@ import { h } from 'preact'; import { expect, describe, it } from 'vitest'; import { Suspense } from 'preact/compat'; import { useId } from 'preact/hooks'; -import { renderToChunks } from '../../src/lib/chunked'; -import { createSubtree, createInitScript } from '../../src/lib/client'; +import { createSubtree, renderToChunks } from '../../src/lib/chunked'; import { createSuspender } from '../utils'; import { VNODE, PARENT } from '../../src/lib/constants'; @@ -34,11 +33,8 @@ describe('renderToChunks', () => { await promise; expect(result).to.deep.equal([ - '
loading...
', - '' + '
', + createSubtree('5', '

it works

') ]); }); @@ -62,10 +58,7 @@ describe('renderToChunks', () => { suspended.resolve(); expect(result).to.deep.equal([ - '
loading...
', - '' + '
' ]); }); @@ -109,11 +102,8 @@ describe('renderToChunks', () => { } expect(result).to.deep.equal([ - '
loading...
', - '' + '
', + createSubtree('16', '

it works

') ]); }); @@ -142,11 +132,8 @@ describe('renderToChunks', () => { await promise; expect(result).to.deep.equal([ - '

id: P0-0

loading...
', - '' + '

id: P0-0

', + createSubtree('24', '

id: P0-1

') ]); }); @@ -182,12 +169,9 @@ describe('renderToChunks', () => { await promise; expect(result).toEqual([ - '

id: P0-0

loading...loading...
', - '' + createSubtree('36', '

id: P0-2

') ]); }); @@ -217,11 +201,8 @@ describe('renderToChunks', () => { await promise; expect(result).to.deep.equal([ - '
loading part 1...
', - '' + '
', + createSubtree('49', '

it works

it works

') ]); }); }); diff --git a/test/compat/stream-node.test.jsx b/test/compat/stream-node.test.jsx index b22cb839..d70acc0c 100644 --- a/test/compat/stream-node.test.jsx +++ b/test/compat/stream-node.test.jsx @@ -2,7 +2,7 @@ import { PassThrough } from 'node:stream'; import { h } from 'preact'; import { expect, describe, it } from 'vitest'; import { Suspense } from 'preact/compat'; -import { createSubtree, createInitScript } from '../../src/lib/client'; +import { createSubtree } from '../../src/lib/chunked'; import { renderToPipeableStream } from '../../src/stream-node'; import { Deferred } from '../../src/lib/util'; import { createSuspender } from '../utils'; @@ -66,11 +66,8 @@ describe('renderToPipeableStream', () => { const result = await sink.promise; expect(result).to.deep.equal([ - '
loading...
', - '' + '
', + createSubtree('5', '

it works

') ]); }); diff --git a/test/compat/stream.test.jsx b/test/compat/stream.test.jsx index 202c26aa..65d7b079 100644 --- a/test/compat/stream.test.jsx +++ b/test/compat/stream.test.jsx @@ -2,7 +2,7 @@ import { h } from 'preact'; import { expect, beforeAll, describe, it } from 'vitest'; import { Suspense } from 'preact/compat'; -import { createSubtree, createInitScript } from '../../src/lib/client'; +import { createSubtree } from '../../src/lib/chunked'; import { renderToReadableStream } from '../../src/stream'; import { Deferred } from '../../src/lib/util'; import { createSuspender } from '../utils'; @@ -82,11 +82,8 @@ describe('renderToReadableStream', () => { const result = await sink.promise; expect(result).toEqual([ - '
loading...
', - '' + '
', + createSubtree('5', '

it works

') ]); }); });