-
Notifications
You must be signed in to change notification settings - Fork 8
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
Replace deprecated method getInnerHTML with getHTML #177
Comments
Hey @DannyMoerkerke thanks for much for reporting this and providing that example of So if I were to summarize in my own words what you are proposing:
Regarding point 1, I think this aligns with an observation @briangrider had while working on #170 that he saw some double wrapping of So in general, with the changes in your PR, no user would ever have to manually do this anymore, yes? this.shadowRoot.innerHTML = `<template shadowrootmode="open"> ... </template>` And the example from the README (the "Get HTML!" output) of manually appending a template would still work? (which based on no other test cases changing in your PR, seems like it would?) const template = document.createElement('template');
template.innerHTML = `
<footer class="footer">
<h4>My Blog © ${new Date().getFullYear()}</h4>
</footer>
`;
class Footer extends HTMLElement {
connectedCallback() {
if (!this.shadowRoot) {
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
}
export default Footer;
customElements.define('wcc-footer', Footer); And so if WCC is going to do auto-wrapping now, at least it would based on actual standard API specifications? Reading the MDN docs, I wasn't sure how to interpret what they were saying, if it would auto-wrap, or just include the I did create a demo to familiarize with If it is intended to do auto-wrapping (or we're proposing this as an explicit value added feature of WCC) I think it would be important to call that out in the documentation / examples as part of the PR, since it's probably not obvious from the outside that setting Just want to avoid any "self-inflicted" double wrapping by user's (still) doing this by educating and informing of WCC's behavior this.shadowRoot.innerHTML = `<template shadowrootmode="open">...</template>` As a bit of an aside, I'm curious if you have any thoughts on this issue - #65? At the time I was stuck on how to get access to getHTML({ serializableShadowRoots = false }) {
const mode = this.shadowRoot.mode ?? false;
return this.shadowRoot && serializableShadowRoots ?
`<template shadowrootmode="${mode}">${this.shadowRoot.innerHTML}</template>` : this.innerHTML;
} Thanks again for putting all this together, and apologies in advance for having such a lengthy reply, but definitely excited to see what we can achieve here, and certainly appreciate the opportunity to get learn about new web APIs! 🧠 |
I haven't been able to log the HTML of those two test cases but I noticed that they failed because the elements that were asserted were not found in the DOM. Removing the hard-coded adding of the
Exactly, the
Yes, this works as expected.
Yes, it is: https://developer.mozilla.org/en-US/docs/Web/API/Element/getHTML
No, the
There are some issues here. First, a shadow root is only serializable (https://developer.mozilla.org/en-US/docs/Web/API/ShadowRoot/serializable) if it's created with the
or when the
Also,
Setting
They should never do this for the reason stated above. Strictly speaking, we should only render the shadow root when it's serializable but users may not specify this when calling On the other hand, we should follow the specs so we should consider adding this to the docs.
I'll have a look.
You're welcome! Thanks for this great project, I'm excited about it as well! |
Hi @DannyMoerkerke, It looks like we're tackling some of the same issues and I wanted to show you what I've been working on with @thescientist13 and get your take. In an attempt to get child element properties working in wcc (and in turn many features of various frameworks like litHTML's child element properties, etc.), I've spent a lot of time updating the DOM shim to work more like the browser implementation of the DOM, specifically, storing childNodes as objects and serializing them when accessing innerHTML rather than storing everything as strings. This simplifies many operations in wcc itself, improves performance by cutting down on the number of parses and serializes in wcc when appending templates and childNodes (instead of using innerHTML), and ultimately, makes it easier to align things with the spec. For example, in regards to simplifying wcc, I was able to simplify renderComponentRoots (and renderToString) pretty significantly. You can see we can remove getInnerHTML (or getHTML), innerHTML, elementHTML, elementTree, hasLight, renderLightDomChildren, and VOID_ELEMENTS with this new implementation: Here's the new dom shim: With this implementation, we don't even need to shim getHTML (but we can if there's a good reason). I would argue that in working toward true isomorphic web components, we should generally be matching the user's browser-based expectations and be forgiving of leaving out the serializable property when instantiating a shadowRoot but maybe respect it if it's specifically set to false. btw, this line here: https://github.com/briangrider/wcc/blob/master/src/dom-shim.js#L230 If we don't shim getHTML, we could achieve a forgiving implementation of the spec like this: class ShadowRoot extends DocumentFragment {
constructor(options) {
super();
this.mode = options.mode ?? 'closed';
// Unlike the spec, default to true to better match browser experience/expectations
this.serializable = options.serializable ?? true;
this.adoptedStyleSheets = [];
}
get innerHTML() {
return this.childNodes ? serialize({ childNodes: this.childNodes }) : '';
}
set innerHTML(html) {
html = this.serializable ? `<template shadowrootmode="${this.mode}" shadowrootserializable>${html}</template>` : html;
this.childNodes = parseFragment(html).childNodes;
}
} Again, I think users should be able to take a complex project (with many web components) that was built for the browser, and render it on the server without modifying each and every component. There are also frameworks people may be using where they don't even have access to the serializable option for their shadow roots. In my opinion, it is worth the slight deviation from spec on this (specifically, defaulting serializable to true instead of false). As a user coming to wcc, I would expect I can just take my working code in the browser and then render it on the server without issue. I imagine having to remind everyone to set serializable to true whenever attaching a shadow seems like it could hurt user adoption. Let me know your thoughts! |
Ah, this is definitely the part I was missing, and was able to confirm as such in @briangrider 's demo, so this all excellent to hear! So know that I've had a chance to dig into #178 a bit deeper, it does seem to cover everything we've been discussing so far with a bonus
I can understand that #178 certainly makes it much easier to achieve all those, and in fact might make it "harder" to not implement them, so while I would traditionally prefer to see So I'll leave it up to you both @briangrider and @DannyMoerkerke how you feel about landing this all at once, and that if we do go with the big bang, that @briangrider you would also need to absorb some of the extra feedback for #171 , mainly adding documentation and / or updating any examples on the WCC website, and validating all the sandbox examples still work and / or need updating. Thoughts? Also happy to setup a chat or start a thread in the Project Evergreen Discord if that will help, but sounds like we have everything we need, and just want to make sure we're all aligned on the path to get there. If we feel good about #178 then I am happy to give it a thorough test against Greenwood's test suite and a couple sample projects, and then we can land that and incorporate part 2 of @briangrider work, which I can revalidate in the same way. From there seems like we should be on fast track to release a new minor version of WCC (v0.16.0). 💯 So cool and super excited for both of your contributions and input here, thank you so much! 🙇♂️ |
Sounds good! So @DannyMoerkerke, what I'd love to take from your PR (since getInnerHTML/getHTML won't exist in WCC anymore) is:
Let me know if this sounds good to everyone! |
Just to make sure I understand what you are saying in point 1 above, auto-wrapping should only happen if the user authors their custom element as such: this.attachShadow({ serializable: true }) If that condition is present, than I think we are ok to match that internally with As far as the order of operations, I would just like to clarify that I would not like the refactor introducing any new behavior / fixes that are not already in the system. I would prefer fixes and changes in behavior of this significance / meaning get isolated to their own change, to avoid having too much context going on as part of one review. So I see two options in regards negotiating the two open PRs that I think we would all want to be on the same page for: Either:
or
My hunch is that we probably want the refactor to land first, which I can handle since it is so foundational, (even if it means slight disruption to the serializable PR) and from there new PRs can come in parallel (element properties, mode, etc). I know it might sounds a little cumbersome, but I just generally prefer atomic commits where possible, in particular with so many moving parts and especially with these new behaviors we're adding / fixing, it will be preferable to only have to review / test / validate one thing at a time. (and also we can start moving individual conversations / feedback back to individual issues as now this issue has kind of taken on the burden of co-ordinating multiple moving parts, and so kind of getting caught in the crossfire). Let's move this operational chat to Discord and / or a call if needed, since I think we all mainly agree on implementation details and outcomes, and so just need to sequence the open items together. |
Yes, I think moving this to Discord is a good idea! |
Hi @briangrider, What I mean by that is if we expect to server-side render web components that use a method like My initial motivation to create the PR was that web components that have their shadow root set through |
Type of Change
Alignment with specs
Summary
Replace the deprecated
Element.prototype.getInnerHTML
withElement.prototype.getHTML
in dom-shim.jsDetails
This issue is in addition to my PR #171
Element.prototype.getInnerHTML
has been deprecated in favor ofElement.prototype.getHTML
(https://developer.mozilla.org/en-US/docs/Web/API/Element/getHTML).Currently in dom-shim.js, the setter for
innerHTML
for theHTMLTemplateElement
automatically and incorrectly adds a<template>
tag with ashadowrootmode
attribute to the HTML content of theHTMLTemplateElement
itself.The result is that the
innerHTML
property of theHTMLTemplateElement
will return its HTML contents including the<template>
tag which is incorrect and not according to the specs as it should only return its contents without this<template>
tag.Element.prototype.getInnerHTML
should be replaced withElement.prototype.getHTML
which provides an options argument that enables the serialization of child nodes that are shadow roots:This also makes sure that Custom Elements that have their shadow roots set through
innerHTML
can be server-side rendered:The text was updated successfully, but these errors were encountered: