sveltejs / svelte

web development for the rest of us
https://svelte.dev
MIT License
79.96k stars 4.25k forks source link

Svelte 5 next.179+: SSR regression with web components #13133

Open sukeshpabolu opened 2 months ago

sukeshpabolu commented 2 months ago

Describe the bug

Facing Uncaught (in promise) HierarchyRequestError: Failed to execute 'appendChild' on 'Node': This node type does not support this method. when style element is included as first child of custom element

Reproduction

here

Logs

Uncaught (in promise) HierarchyRequestError: Failed to execute 'appendChild' on 'Node': This node type does not support this method.

System Info

stackblitz 
System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 18.20.3 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 10.2.3 - /usr/local/bin/npm
    pnpm: 8.15.6 - /usr/local/bin/pnpm
  npmPackages:
    svelte: 5.0.0-next.178 => 5.0.0-next.178

Severity

blocking an upgrade

trueadm commented 2 months ago

One thing we could do here is detect a custom-element as the parent at compile time and insert different DOM traversal methods that allow for things like <style> elements that might occur between.

dummdidumm commented 2 months ago

There also have been issues with web components + hydration in Svelte 4, where attributes were adjusted before the hydration came across it. It's definetly a tricky area, and something where a bit more robustness/"leave it alone" wouldn't hurt.

paoloricciuti commented 2 months ago

I'm testing this a bit and it doesn't seem to ever worked in any version of svelte 5, it's throwing some version of this hydration error since the beginning.

dummdidumm commented 2 months ago

Sound about right - would've been surprised that this ever worked. Giving this the 5.x milestone, but if someone wants to fix it before 5.0 they're welcome to.

SukeshP1995 commented 2 months ago

I'm testing this a bit and it doesn't seem to ever worked in any version of svelte 5, it's throwing some version of this hydration error since the beginning.

It worked in 178. If you can suggest a temp fix that will be good atleast

paoloricciuti commented 2 months ago

I'm testing this a bit and it doesn't seem to ever worked in any version of svelte 5, it's throwing some version of this hydration error since the beginning.

It worked in 178. If you can suggest a temp fix that will be good atleast

image

This is in your reproduction, installing svelte@5.0.0-next.178...as you can see the error about hydration is still there. Did it behave differently than the latest versions?

paoloricciuti commented 2 months ago

Ok now i think i get what you are saying @SukeshP1995 ...after 179 the whole app goes blank, before it was showing. The problem however is that your custom element is still not hydrated properly so whatever svelte code is inside or even after your custom element will not work properly.

paoloricciuti commented 2 months ago

I'm testing this a bit and it doesn't seem to ever worked in any version of svelte 5, it's throwing some version of this hydration error since the beginning.

It worked in 178. If you can suggest a temp fix that will be good atleast

Speaking of this i have to admit i never actually worked extensively with web components but if i can have an intuition about what you are trying to do with lightStyleCss is to add some css for the light dom right? If so this doesn't cause hydration issues even in the latest version of svelte

connectedCallback() {
  const lightStyles = document.createElement('style');
  lightStyles.slot = 'light-styles';
  lightStyles.innerHTML = lightStyleSheet;
-  this.append(lightStyles.cloneNode(true));
+  document.head.append(lightStyles.cloneNode(true));
}

but again i don't know if this is feasible

trueadm commented 2 months ago

I still believe my post above should resolve this.

SukeshP1995 commented 2 months ago

I still believe my post above should resolve this.

Hi, the web components are in a package (private). If it had been my own I would have found a different way to inject those styles

SukeshP1995 commented 2 months ago

I'm testing this a bit and it doesn't seem to ever worked in any version of svelte 5, it's throwing some version of this hydration error since the beginning.

It worked in 178. If you can suggest a temp fix that will be good atleast

Speaking of this i have to admit i never actually worked extensively with web components but if i can have an intuition about what you are trying to do with lightStyleCss is to add some css for the light dom right? If so this doesn't cause hydration issues even in the latest version of svelte


connectedCallback() {

  const lightStyles = document.createElement('style');

  lightStyles.slot = 'light-styles';

  lightStyles.innerHTML = lightStyleSheet;

-  this.append(lightStyles.cloneNode(true));

+  document.head.append(lightStyles.cloneNode(true));

}

but again i don't know if this is feasible

I will try this and see, but FYI the web components are in a seperate internal package so I have to patch those then

paoloricciuti commented 2 months ago

I will try this and see, but FYI the web components are in a seperate internal package so I have to patch those then

Yeah i've imagined that...unfortunately hydration requires the order of elements to be consistent between SSR and the hydration phase...we can see if we can implement what Dominic proposed but until then you might need to find ways around it. :(

sukeshpabolu commented 2 months ago

I will try this and see, but FYI the web components are in a seperate internal package so I have to patch those then

Yeah i've imagined that...unfortunately hydration requires the order of elements to be consistent between SSR and the hydration phase...we can see if we can implement what Dominic proposed but until then you might need to find ways around it. :(

I started pnpm patching my web components 😩. (they are only 4 of them)

7nik commented 2 months ago

What about adoptedStyleSheets? It inserts styles without creating a node in the DOM.

  connectedCallback() {
    const sheet = new CSSStyleSheet();
    sheet.replaceSync(lightStyleSheet);
    // add styles to the closest shadowRoot or document
    this.getRootNode().adoptedStyleSheets = [sheet];
  }

It's even recommended to hoist sheet to re-use it.

SukeshP1995 commented 2 months ago

Every time I use the component it is creating the style tag. I am having a bunch of style tags now 🤣