diff --git a/.changeset/calm-loops-render.md b/.changeset/calm-loops-render.md new file mode 100644 index 00000000000..42b7133b250 --- /dev/null +++ b/.changeset/calm-loops-render.md @@ -0,0 +1,5 @@ +--- +'@qwik.dev/core': patch +--- + +fix: render nested Each components on the server diff --git a/packages/docs/src/repl/bundler/repl-bundler-worker.ts b/packages/docs/src/repl/bundler/repl-bundler-worker.ts index 3efcdca4b61..5f5fcf1facb 100644 --- a/packages/docs/src/repl/bundler/repl-bundler-worker.ts +++ b/packages/docs/src/repl/bundler/repl-bundler-worker.ts @@ -186,7 +186,7 @@ async function performBundle(message: BundleMessage): Promise { debug, srcInputs, entryStrategy, - experimental: ['suspense'], + experimental: ['each', 'show', 'suspense'], manifestOutput: (m: any) => { result.manifest = m; }, @@ -233,7 +233,7 @@ async function performBundle(message: BundleMessage): Promise { debug, srcInputs, entryStrategy, - experimental: ['suspense'], + experimental: ['each', 'show', 'suspense'], }), replResolver(deps, { srcInputs, buildMode, replId }, 'ssr'), replMinify(buildMode), diff --git a/packages/qwik/src/core/control-flow/each.ts b/packages/qwik/src/core/control-flow/each.ts index f317618cdcf..f916db240f1 100644 --- a/packages/qwik/src/core/control-flow/each.ts +++ b/packages/qwik/src/core/control-flow/each.ts @@ -33,10 +33,10 @@ export const eachCmpTask = async ({ track }: TaskCtx) => { const context = tryGetInvokeContext()!; const host = context.$hostElement$!; const container = context.$container$!; - markVNodeDirty(container, host, ChoreBits.RECONCILE); + const renderPromise = markVNodeDirty(container, host, ChoreBits.RECONCILE); const isSsr = qTest ? isServerPlatform() : isServer; if (isSsr) { - await container.$renderPromise$; + await renderPromise; } }; diff --git a/packages/qwik/src/core/shared/vnode/vnode-dirty.ts b/packages/qwik/src/core/shared/vnode/vnode-dirty.ts index 4a030e739fa..a36a65c6a57 100644 --- a/packages/qwik/src/core/shared/vnode/vnode-dirty.ts +++ b/packages/qwik/src/core/shared/vnode/vnode-dirty.ts @@ -9,6 +9,7 @@ import { isServerPlatform } from '../platform/platform'; import type { Container } from '../types'; import { throwErrorAndStop } from '../utils/log'; import { isPromise } from '../utils/promises'; +import type { ValueOrPromise } from '../utils/types'; import { getNearestCursorBoundary, getOwnCursorBoundary, @@ -136,7 +137,7 @@ export function markVNodeDirty( vNode: VNode | ISsrNode, bits: ChoreBits, cursorRoot: VNode | null = null -): void { +): ValueOrPromise { const prevDirty = vNode.dirty; vNode.dirty |= bits; if (isSsrNodeGuard(vNode)) { @@ -146,7 +147,7 @@ export function markVNodeDirty( ? container.$renderPromise$.then(() => result) : result; } - return; + return result; } const isRealDirty = bits & ChoreBits.DIRTY_MASK; // If already dirty, no need to propagate again diff --git a/packages/qwik/src/core/tests/each.spec.tsx b/packages/qwik/src/core/tests/each.spec.tsx index 18704939416..2a118f03070 100644 --- a/packages/qwik/src/core/tests/each.spec.tsx +++ b/packages/qwik/src/core/tests/each.spec.tsx @@ -43,6 +43,39 @@ describe.each([ ); }); + it('should render nested each items', async () => { + const Cmp = component$(() => { + return ( +
+ String(index)} + item$={(items) => ( + String(index)} + item$={(item) => {item}} + /> + )} + /> +
+ ); + }); + + const { document } = await render(, { debug }); + await expect(document.getElementById('loop')).toMatchDOM( +
+ a + b + c + d +
+ ); + }); + it('should render long each item', async () => { const Cmp = component$(() => { return (