Skip to content

Commit

Permalink
fix: projection siblings serialization
Browse files Browse the repository at this point in the history
  • Loading branch information
Varixo committed Jan 6, 2025
1 parent 5bcaf63 commit dae54f6
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 32 deletions.
5 changes: 5 additions & 0 deletions .changeset/friendly-sloths-return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@qwik.dev/core': patch
---

fix: projection siblings serialization
90 changes: 64 additions & 26 deletions packages/qwik/src/core/tests/projection.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import { domRender, ssrRenderToDom, trigger } from '@qwik.dev/core/testing';
import { cleanupAttrs } from 'packages/qwik/src/testing/element-fixture';
import { beforeEach, describe, expect, it } from 'vitest';
import { vnode_getNextSibling } from '../client/vnode';
import { vnode_getNextSibling, vnode_getProp, vnode_locate } from '../client/vnode';
import { HTML_NS, SVG_NS } from '../shared/utils/markers';

const DEBUG = false;
Expand Down Expand Up @@ -101,9 +101,9 @@ describe.each([
});
const { vNode } = await render(<Parent />, { debug: DEBUG });
expect(vNode).toMatchVDOM(
<Component>
<Component>
<Projection>default-value</Projection>
<Component ssr-required>
<Component ssr-required>
<Projection ssr-required>default-value</Projection>
</Component>
</Component>
);
Expand All @@ -117,9 +117,9 @@ describe.each([
});
const { vNode } = await render(<Parent />, { debug: DEBUG });
expect(vNode).toMatchVDOM(
<Fragment>
<Fragment>
<Fragment>projection-value</Fragment>
<Fragment ssr-required>
<Fragment ssr-required>
<Fragment ssr-required>projection-value</Fragment>
</Fragment>
</Fragment>
);
Expand Down Expand Up @@ -951,12 +951,12 @@ describe.each([

const { vNode } = await render(<SlotParent />, { debug: DEBUG });
expect(vNode).toMatchVDOM(
<Component>
<Component>
<Component>
<Component ssr-required>
<Component ssr-required>
<Component ssr-required>
<div>
<Projection>
<Projection>
<Projection ssr-required>
<Projection ssr-required>
<span q:slot="start">START</span>
</Projection>
</Projection>
Expand Down Expand Up @@ -993,12 +993,12 @@ describe.each([

const { vNode } = await render(<SlotParent />, { debug: DEBUG });
expect(vNode).toMatchVDOM(
<Component>
<Component>
<Component>
<Component ssr-required>
<Component ssr-required>
<Component ssr-required>
<div>
<Projection>
<Projection>
<Projection ssr-required>
<Projection ssr-required>
<span q:slot="start">START</span>
</Projection>
</Projection>
Expand Down Expand Up @@ -1105,16 +1105,16 @@ describe.each([
const { vNode } = await render(<Parent />, { debug: DEBUG });

expect(vNode).toMatchVDOM(
<Component>
<Fragment>
<Component>
<Projection>
<Component>
<Component>
<Projection>
<Component ssr-required>
<Fragment ssr-required>
<Component ssr-required>
<Projection ssr-required>
<Component ssr-required>
<Component ssr-required>
<Projection ssr-required>
<span>
<Projection>
<Fragment>{'INSIDE THING'}</Fragment>
<Projection ssr-required>
<Fragment ssr-required>{'INSIDE THING'}</Fragment>
</Projection>
</span>
</Projection>
Expand Down Expand Up @@ -1986,6 +1986,44 @@ describe.each([
});
});

it('should serialize all component props next to projection', async () => {
const InnerCmp = component$(() => {
return <Slot />;
});

const Cmp = component$(() => {
return (
<div>
<InnerCmp>
{/* ^ This component */}
<div></div>
</InnerCmp>
<Slot />
</div>
);
});

const Parent = component$(() => {
const counter = useSignal(0);
return (
<>
<Cmp key={counter.value}>
<div></div>
</Cmp>
<button id="counter" onClick$={() => counter.value++}></button>
</>
);
});

const { container } = await render(<Parent />, { debug: DEBUG });

if (ssrRenderToDom === render) {
const CmpVNode = vnode_locate(container.rootVNode, '4A');
const renderProp = vnode_getProp(CmpVNode, 'q:renderFn', null);
expect(renderProp).not.toBeNull();
}
});

describe('regression', () => {
it('#1630', async () => {
const Child = component$(() => <b>CHILD</b>);
Expand Down
4 changes: 2 additions & 2 deletions packages/qwik/src/core/tests/use-styles-scoped.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -374,8 +374,8 @@ describe.each([
expect(vNode).toMatchVDOM(
<Component>
<div class={`${(globalThis as any).rawStyleId1} container`}>
<Fragment>
<Component>
<Fragment ssr-required>
<Component ssr-required>
<div class={`${(globalThis as any).rawStyleId2} container`}>Hello world 2</div>
</Component>
</Fragment>
Expand Down
6 changes: 2 additions & 4 deletions packages/qwik/src/server/ssr-container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -458,12 +458,10 @@ class SSRContainer extends _SharedContainer implements ISSRContainer {

openProjection(attrs: SsrAttrs) {
this.openFragment(attrs);
const vNode = this.currentElementFrame?.vNodeData;
if (vNode) {
vNode[0] |= VNodeDataFlag.SERIALIZE;
}
const componentFrame = this.getComponentFrame();
if (componentFrame) {
// TODO: we should probably serialize only projection VNode
this.serializationCtx.$addRoot$(componentFrame.componentNode);
componentFrame.projectionDepth++;
}
}
Expand Down

0 comments on commit dae54f6

Please sign in to comment.