-
Notifications
You must be signed in to change notification settings - Fork 295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Shadow: Specify when slotchange
fires
#447
Comments
Why is it not precise? |
@annevk Maybe I am not understanding the spec, that is entirely possible. If it is specced, do you mind telling me which browser is behaving correctly so I can file bugs against the others? |
However, maybe we can have a discussion if it is possible/feasible to change the spec to the behavior I describe below or help me understand why that is not a good idea™️ |
As far as I can tell the specification consistently fires slotchange however the tree was created. Meaning only "ShadyDOM" is correct (though I haven't looked at the timing). If your understanding is different you'll have to tell me how you arrived at that conclusion. |
I think the following chromium bug is related: I believe that the current Blink's behavior satisfies spec-conformance. From #229 (comment)
If we change it to:
Then, I think the spec's behavior matches that of Shady DOM. |
See WICG/webcomponents#288 (comment) by @rniwa for why we suppress in that case. I'm okay with changing this if you're all agreed (including @rniwa) we should change this. Anyone interested in writing tests? |
Just want to reemphasize that I am arguing from a developer experience perspective here, and that the current state is unexpected (and inconvenient). I’d actually be happy to take this opportunity learn to write tests and help out that way. I’m sure one of my colleagues could help me get started here. (@domenic?) |
I appreciate you filing the issue. I just wasn't sure at first what the problem was, but @hayatoito stepping through the algorithms in the Chrome bug made it more clear. |
http://web-platform-tests.org/ has documentation on writing tests. It's probably worth looking at existing tests once you've got the framework running locally as the easiest way to figure out how to write them. |
The other thing to do is check through the existing tests to make sure none of them test the currently-specced behavior; if they do they need to change. Happy to help more over IRC or Hangouts or whatever once I'm in the office (~an hour or so). Although those docs should help you get started. |
I opened a PR for a web-platform-tests that tests for the ShadyDOM behavior. Pending consensus in this issue :) |
Thanks. I need some time on investigating how Blink can fire a event in such a case. I thought that is doable, but I am not 100% sure. I need to do an experiment. I think the interoperability is the most important here. I am open to any opinions. |
I have roughly implemented the behavior which I think is being proposed; when inserting a slot, and one or more slotables are assigned to the slot at this timing, we fire slotchange on the slot. If we can agree this change, I am happy to send a PR to DOM Standard, write a WPT, and update Blink's behavior. I think backward compatibility risk is very low. |
WebKit's behavior is not to fire Here's my thought.
Firing |
Note: While preparing a demo for this reply, I found out that things become even more inconsistent depending on whether you create your slots in the constructor or
@hayatoito Thanks for investigating. Very glad to hear that the behavior is technically possible and feasible. @rniwa As I said, my main goal is consistency, with a preference for changing the behavior to always firing ConsistencyThe behavior of
Unless you are intimately familiar with the intricacies of Custom Elements and ShadowDOM, this is going to trip up and annoy developers. When developing generic components, you might write code that works fine during development, but because users include your CE script at a different point in the page, things suddenly stop working. A similar argument can be made for Always firingTake a look at this demo, which is a stripped down version of a tab panel component I am working on. I’m using ShadowDOM to “reshuffle” the children as a technique for graceful degradation. If JS is disabled, the tabs function as headings for the different sections. So in the markup tabs and panels are interleaved. I use ShadowDOM do group tabs and panels. I need to be notified about new elements because I need to generate IDs and semantically link tabs and panels using I am aware that CE lifecycle callbacks are something different from ShadowDOM events, but the fact that |
Those are some good points but I think we need to hear opinions of other stake holders. If they're all okay with this change, we can go ahead and make the spec change. |
Definitely agree with making this change. It's much easier to create an element when the developer only has to consider one processing model for basic lifecycle.
One could similarly argue that |
Okay, given the use cases and multiple developers saying the current behavior is confusing, I'd now argue that we should make this spec change. |
Sounds like noone is opposed to the change 🎉 @hayatoito Do you mind creating the PR for the spec? I’ll happily take care of the PR for the tests (web-platform-tests/wpt#5705). |
Sure. Let me make a PR to DOM Standard. I'll update Blink's behavior after it gets merged. Thank you all for making this change happen. Especially, huge kudos for @surma. 👍 |
@hayatoito @surma @rniwa so should we keep suppressing for removal slots or should we just remove the concept of suppressing altogether? |
From the implementor's perspective, if we remove suppressing for slots removal, the engine will need to do an additional check (and additional potential slotchange event firing). Unless there is a good use case for slotchange at "slot removal", it might be better to keep suppressing it. |
IMHO, it's better to have the same behavior in all cases: "If the nodes distributed to the slot changed, then 'slotchange' fires." I don't think the inconsistency introduced by adding the special case "However, if the nodes distributed to a slot changed because that slot was removed from a tree, then 'slotchange' does not fire." is justified by avoiding the performance cost of an extra event. |
@bicknellr why not? |
Okay, if someone still feels strongly we should remove suppression for slots removal I suggest they file a new issue and we can tackle that separately. |
I think we should get rid of the suppression completely given that would simplify the spec & implementation. I can't think of a reason why we'd want to keep it just for the removal case. |
It seems somewhat reasonable. I think it would be even better if |
I see. I am okay to disable As of now, the functional APIs which are visible to outside are:
I think that is all. We should update DOM Standard to disable 1 and 2. I am happy to update PR to DOM Standard if this is okay. I think this change doesn't have any practical impact on web developers. |
I like this. Disabling @hayatoito I think that change should be covered in a separate WPT for ShadowDOM. Do you want to add those? |
@surma I will add (and/or update) WPT to cover these changes. |
Yeah, I really doubt that anyone is relying on slot element working when it's detached from a shadow tree. |
I roughly implemented what we roughly agreed here. I am now feeling that supporting Let me update PR to DOM Standard. |
Don't consider a slot's children as fallback contents if the slot is not in a shadow tree. Such a slot doesn't signal a slot change even if its children are updated. This patch also remove a suppress signaling flag for a slot change, and always signal a slotchange when a slot's assigned nodes are changed. Fixes whatwg#447.
Don't consider a slot's children as fallback contents if the slot is not in a shadow tree. Such a slot doesn't signal a slot change even if its children are updated. This patch also remove a suppress signaling flag for a slot change, and always signal a slotchange when a slot's assigned nodes are changed. Fixes whatwg#447.
A slot's children are no longer considered as the slot's fallback contents if the slot is not in a shadow tree. Such a slot no longer signals a slot change even if its children are updated. This patch also removes a concept of suppress signaling flag for a slot change entirely. A slot change is always signaled when a slot's assigned nodes are changed. Fixes whatwg#447.
Are you also updating the web platform tests? |
Yes, I am now working on that. Some amount of tests need to be updated. |
A slot's children are no longer considered as the slot's fallback contents if the slot is not in a shadow tree. Such a slot no longer signals a slot change even if its children are updated. This patch also removes a concept of suppress signaling flag for a slot change entirely. A slot change is always signaled when a slot's assigned nodes are changed. Fixes whatwg#447.
FYI: PR for web platform tests is web-platform-tests/wpt#5954 |
…nge concept Rewrite the core part of the Shadow DOM v1 distribution engine so that distribution recalculation happens *if and only if* a newly-defined concept of a slotchange actually happens. Benefits: - Performance improvement - Eliminated code complexity - Becomes spec-compliant (as a side effect, this is one of the motivations of rewriting) 1. Performance improvement: The result of PerformanceTests/ShadowDOM performance tests: v1-distribution-disconnected-and-reconnected Before CL: 201.4 ms After CL: 41.7 ms (5x times faster) 2. Eliminated code complexity: Though I have a plan to explain the detail about how the v1 distribution engine works in core/dom/shadow/README.md file, let me explain the benefits of the new design here other than the performance tests: - Eliminated false-positive for setting a dirty flag for distribution recalculation Before this CL, the engine sets a dirty flag for distribution conservatively. As a result, a false-positive can happen, which has been difficult to avoid because distribution is not a local effect. We don't have much budget of time in DOM mutation. After this CL, the engine sets a dirty flag if and only if a slotchange actually happens. No longer needs to set a dirty flag in other places. Note that the engine only detects the fact of "a slotchange happens", but it doesn't try to know an exact distributed nodes for each slot at the timing of DOM mutation so that DOM mutation should not be blocked more than necessary. Distributed nodes are lazily-calculated later. - Life cycle of slot's distribution nodes became more clear The engine no longer clears out each slot's distributed nodes in shadow-including descendant subtrees when the subtree is disconnected from the parent tree. e.g. We don't need to update distribution for a custom element which has deeply nested other custom elements inside of it at each insertion/removal from a tree. The performance test's improvement came mostly from this result. - Eliminated a lot of tricky code which is needed to support <slot> in non-shadow trees. I successfully stopped to support <slot> in non-shadow trees, and upstreamed the decision to WHATWG DOM Standard [1], getting agreement from other browser vendors [2]. I have already updated web platform tests [3] too. These tests no longer fail after this CL. The support of <slot> in non-shadow trees has been difficult to support, and has been the cause of crashes. We no longer have to fight with crashes. 3. Becomes spec-compliant (as a side effect, this is one of the motivations of rewriting) From the Web developers' perspective, this CL shouldn't have any practical impact, as long as a slot element is only used in shadow trees. The only practical visible change is: A slotchange event is always signaled as a microtask whenever a slot's distributed nodes are changed. For example, when a slot is inserted or removed from a tree, a slotchange event can be fired. Before this CL, a slotchange is never fired in this case. See DOM Standard issue [2] for details, which is rather a feature request from web developers. This CL satisfies this requirement, as an intended side effect. I am aware that it would be better to separate the engine rewriting from the user visible changes, but it would require unnecessary efforts to keep the old behavior in the new engine. Thus, I put all together. Supporting [2] is one of the reasons I decided to rewrite the engine. Note that only Shadow DOM v1 can get these benefits. Shadow DOM v0 is out of the scope of this CL. - [1] DOM Standard change: whatwg/dom#459 - [2] DOM Standard issue: whatwg/dom#447 - [3] Web platform tests change: web-platform-tests/wpt#5954 Links: Change-Id: I41f29e781185c46739377ab3939d20fa24fb69bf Reviewed-on: https://chromium-review.googlesource.com/532734 Commit-Queue: Hayato Ito <hayato@chromium.org> Reviewed-by: Takayoshi Kochi <kochi@chromium.org> Reviewed-by: Kent Tamura <tkent@chromium.org> Cr-Commit-Position: refs/heads/master@{#480013}
A slot's children are no longer considered as the slot's fallback contents if the slot is not in a shadow tree. Such a slot no longer signals a slot change even if its children are updated. This patch also removes a concept of suppress signaling flag for a slot change entirely. A slot change is always signaled when a slot's assigned nodes are changed. Fixes whatwg#447.
A slot's children are no longer considered as the slot's fallback contents if the slot is not in a shadow tree. Such a slot no longer signals a slot change even if its children are updated. This patch also removes a concept of suppress signaling flag for a slot change entirely. A slot change is always signaled when a slot's assigned nodes are changed. Fixes whatwg#447.
A slot's children are no longer considered as the slot's fallback contents if the slot is not in a shadow tree. Such a slot no longer signals a slot change even if its children are updated. This patch also removes a concept of suppress signaling flag for a slot change entirely. A slot change is always signaled when a slot's assigned nodes are changed. Fixes #447.
It's more useful for library authors.
It's easy to imagine scenarios. Using our imagination or example, imagine a game. When the user's monster character gets to a higher skill level, it earns an extra hand. Objects like guns or tools could be placed into this new hand (i.e. slotted into this new slot). If the character is injured, maybe it's hand gets severed from battle, then the hand is removed (the slot is removed but the perhaps the gun remains in inventory). <monster-character position="20 40 50" rotation="0 40 0">
<weapon-rifle slot="hand-1">
</weapon-rifle>
<weapon-pistol slot="hand-2">
</weapon-pistol>
<weapon-sword slot="hand-3">
</weapon-sword>
</monster-character>
In A-Frame mentioned they don't intend to support Shadow DOM... But, if they did... they would need to understand the composed tree in order to render that with Three.js. |
I forgot to add, |
At the moment, in infamous, I'm observing addition/removal of slots with MO, and using If This is my perspective as someone using Web Components. If I could easily detect distributed and undistributed nodes with only a It seems to me that it might be more helpful in some cases to have a A Custom Element (a reusable component) owns its whole shadow root, so it would be okay to have shadow root events like this, because the whole logic is still encapsulated inside the Custom Element. The event of "elements being distributed into a shadow root" seems great for more generic whole-shadow-root logic, and |
@trusktr if you want a change in behavior it would be much better to file a new issue. We're not tracking closed issues. |
@annevk I don't have a new issue per se, I'm just pointing out use cases that might be useful to consider (because @hayatoito had asked, but not many were provided). After the changes in #459, how does the above table change? Is everything |
@trusktr Blink has already implemented the spec change. You can confirm the new behavior in Blink. If you find a bug, I would appreciate if you can file a bug for Blink. |
If anyone else is looking for a workaround for this issue on Safari, try checking for |
I will test soon on my end when I circle back to ShadowDOM support for my lib. What should I expect from the changes? Is everything in the above table |
Safari, Chrome and ShadyDOM currently exhibit different behavior when
slotchange
does and does not fire. As far as I understand the spec, it is not precisely spec’d, meaning all these current behaviors are technically spec compliant, but can be very frustrating for developers.Demo 1: Slots are created in the constructor
Demo 2: Slots are creatred in
connectedCallback
Which browser fires
slotchange
under what circumstances?connectedCallback
, parser creates elementconnectedCallback
, element gets upgraded(ShadyDOM was tested using Firefox).
While my main concern is consistency across browsers, I like ShadyDOM’s behavior best in terms of DX as it is consistent with how
attributeChangeCallback
in that it fires upon initialization. This would allow developers to have their update logic in theslotchange
handler and they wouldn’t need to manually detect silently slotted elements inconnectedCallback()
./cc @hayatoito
The text was updated successfully, but these errors were encountered: