ionic-team / stencil

A toolchain for building scalable, enterprise-ready component systems on top of TypeScript and Web Component standards. Stencil components can be distributed natively to React, Angular, Vue, and traditional web developers from a single, framework-agnostic codebase.
https://stenciljs.com
Other
12.56k stars 785 forks source link

bug: The child component are not properly placed within the slots. #5308

Closed masungmin-dev closed 9 months ago

masungmin-dev commented 9 months ago

Prerequisites

Stencil Version

4.12.0

Current Behavior

There is a child component responsible for rendering a span element, and a parent component that draws a border with the shadow option set to false

When the parent component has shadow set to false, the child web component or HTMLElement will not be placed exactly where we want it.

The summarized environment where the issue occurs is as follows:

As you can see here, some of the child components inserted into the slot of the parent component with shadow:false are rendered outside the border.

Jan-31-2024 13-49-52

Edit: When more testing was done, I Found The parent's lifecycle end prematurely, triggering componentDidLoad. and then The "connectedCallback()" of child elements is fired who they are not with right positioned.

Expected Behavior

When bundling a Stencil component, built with the shadow:false option as dist-custom-element, all child components should be rendered in their correct positions

System Info

System: node 16.20.1
    Platform: darwin (23.2.0)
   CPU Model: Apple M1 Max (10 cpus)
    Compiler: /Users/my/workspace/stencil4/node_modules/@stencil/core/compiler/stencil.js
       Build: 1705946070
     Stencil: 4.11.0 🍝
  TypeScript: 5.3.3
      Rollup: 2.56.3
      Parse5: 7.1.2
      jQuery: 4.0.0-pre
      Terser: 5.27.0

Steps to Reproduce

I made a small reproduction case for this, here

  1. clone reproduction case
  2. npm install
  3. npm run dev

Code Reproduction URL

https://github.com/masungmin-dev/stencil-with-dist-custom-element

Additional Information

No response

tanner-reits commented 9 months ago

Hey there @masungmin-dev! Thanks for reporting this issue. I can confirm the behavior you're seeing, but we're going to close this out. Stencil is moving toward dropping support for slots in non-encapsulated components (i.e. if neither shadow: true nor scoped: true is set). We will continue to support slots for scoped components.

I checked this out in your reproduction by changing the s-noshadow-border component to a scoped component and that worked as expected. Alternatively, you can keep the component with no encapsulation if you wrap all the children to be slotted in a single div element.

Hope that helps!

kerryj89 commented 9 months ago

Hi @tanner-reits,

Just to be sure I understand, are you saying that Stencil is planning on dropping support/emulation for the slots feature in the light DOM? I chose to go with Stencil because of this slot-in-the-light-DOM ability. It allows us to sidestep all the shadow DOM headaches while keeping to the componental model between our products using different stacks (our oldest app is 15 years old and would require tremendous effort to completely buy into the shadow DOM).

With you closing this issue, it seems that this change is on the horizon (assuming I understood right) - how soon do you think this transition will happen and is there some discussion thread over this change that I can read up on to better prepare?

rwaskiewicz commented 9 months ago

Hey @kerryj89 👋

Yes, our current plan is to drop support for slot emulation for component's that do not use scoped: true (we'll continue to support shadow: true, as that uses native web component technology). Specifically, we plan on dropping slot emulation support for components that are declared as such:

@Component({ tag: 'my-component' })
@Component({ tag: 'my-component', shadow: false })
@Component({ tag: 'my-component', scoped: false })
@Component({ tag: 'my-component', shadow: false, scoped: false })

Our recommendation is going to be folks using one of the declaration styles to use scoped: true like so:

@Component({ tag: 'my-component', scoped: true })

This continues to use the light DOM while emulating CSS style encapsulation and slot functionality.

We'll be opening an RFC in the next few weeks to get feedback from the community. Based on the feedback we receive from the community, our direction with regard this functionality is subject to change.

This change is not imminent - it's planned for Stencil v5, which I don't anticipate being ready until the second half of this year.

masungmin-dev commented 9 months ago

Thanks to Response @tanner-reits , @rwaskiewicz

Unfortunately, It appears that wrapping the content with a div could lead to a limited experience, restricting the freedom to use web components.

The "scoped" solution is not currently what I am looking for, and the problem remains unresolved. In the actual usage environment, this issue arises even with a smaller number of instances.

Upon further testing, I identified additional symptoms:

I've concluded that this might be an issue related to timing and DOM tree parsing. If you use defer or define after the domContentLoaded event when DOM tree parsing is finished, there will be no problem.

so this problem seems to be due to the early loading(and excute define) time, rather than being a specific issue with the mentioned dist-custom-element type. It could potentially occur in different environments based on bundling methods and define timing.

I'm using a non-ESM environment, executing defineCustomElements within the head tag to draw the DOM as quickly as possible.

I'm hoping for assistance in this regard, as I aim to load faster than the defer or domContentLoaded timing.

I'm currently exploring other potential solutions. While it's uncertain if this information will be helpful to the Stencil team, I'm sharing the additional details I've gathered in the hope that it might provide some assistance.

rwaskiewicz commented 9 months ago

@masungmin-dev

so this problem seems to be due to the early loading(and excute define) time, rather than being a specific issue with the mentioned dist-custom-element type. It could potentially occur in different environments based on bundling methods and define timing.

Could you update your reproduction case for us? If this is the case, we'd be happy to take a look!

masungmin-dev commented 9 months ago

@rwaskiewicz

You can make the following modifications in the reproduction case. (I added comments so you can see) There are no major changes.

The problem is that the parent searches for the child nodes before Chrome browser finishes parsing the DOM. This problem also causes the child's life cycle to escape from that of the parent. (As I mentioned earlier, I checked this issue by checking the core logic of stencils in the built file.)

The way to solve this by avoiding the current symptoms is as follows. (Unfortunately, it’s not a solution for me) Any of the following cases will do.

However, this is an act of delaying the define timing, so it did not render quickly in real case because it delays the render.