denoland / fresh

The next-gen web framework.
https://fresh.deno.dev
MIT License
12.15k stars 620 forks source link

Fragment inside if (IS_BROWSER) doesn't replace an SSR-rendered else branch, keeping both rendered in the end #2237

Open king8fisher opened 7 months ago

king8fisher commented 7 months ago
"$fresh/": "https://deno.land/x/fresh@1.6.1/",
"preact": "https://esm.sh/preact@10.19.2",
"preact/": "https://esm.sh/preact@10.19.2/",
"@preact/signals": "https://esm.sh/*@preact/signals@1.2.1",
"@preact/signals-core": "https://esm.sh/*@preact/signals-core@1.5.0",

Minimal reproducible example

https://github.com/king8fisher/bug-report-deno-fresh-fragment

marvinhagemeister commented 7 months ago

Something odd is going on. I can reproduce the issue, but haven't found the root cause yet.

CAYdenberg commented 7 months ago

@marvinhagemeister Doesn't preact need an actual DOM node to render in to? If the outer element of an island is just a Fragment, what gets passed to preact's root render function?

marvinhagemeister commented 7 months ago

We always pass a fake dom node as the root element that doesn't exist in the actual Dom when reviving islands. It's been on invisible comment markers as the boundary. This is done to support sibling islands in the same container with potentially static nodes in between. It shouldn't matter what the outer element looks like.

debel commented 3 months ago

I think I hitting something similar with a pet project I'm working on.

Basically, I have a server component that renders a list of islands, but the islands are never re-rendered with the client components after the initial server render.

e.g.

<ServerList>
  {serverDataList.map(dataPoint => <IslandListItem {...dataPoint} />)}
</ServerList>

The IslandListItem has a IS_BROWSER check and renders the server branch, but the other branch is never rendered afterwards. What am I doing wrong?

EDIT: if I remove the IS_BROWSER branch I get this error in the browser console:

main.ts:196 Uncaught DOMException: Failed to execute 'insertBefore' on 'Node': The node before which the new node is to be inserted is not a child of this node.
    at hideMarker (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:2986)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:5502)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:6910)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:6910)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:6910)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:6910)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:6910)
    at _walkInner (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:6910)
    at revive (http://localhost:8000/_frsh/js/599147f94550f65a5921ad1cde134f162a5743d4/main.js:47:2071)
    at http://localhost:8000/:1:21255

The page renders "correctly", but is not interactive at all.

The issue disappears if I make ServerList an island, I can still fetch the data on the server, but that seems pretty weird to me... (sorry for the multiple edits...)