-
Notifications
You must be signed in to change notification settings - Fork 955
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
Upgrade disconnected custom elements before setting properties on them. #442
Conversation
Tests are failing in Safari 10 as expected. This shows the problem with this approach... The other solutions are much more invasive though |
I think the proper solution is to defer the responsibility of 'fixing' instance properties to the Custom Element. This is required anyway for Custom Elements to function with deferred upgrades (through e.g. lazy imports). I think the following pattern is fairly reasonable/common: class MyApp {
get template() {
return html`
<div id="pages">
<login-page></login-page>
<main-page user=${user}></main-page>
<other-page user=${user}></other-page>
</div>
`;
}
onRouteChange(newPage) {
import(newPage).then(
() => {
this.pages[newPage].setAttribute('active', '');
this.pages[oldPage].removeAttribute('active');
}
);
}
} This will break the Custom Elements no matter what lit-html does, because at the time of first render, the page elements are not registered as custom elements (because they are not yet imported). If the Custom Element baseclass contains something like this in the constructor, it handles all these problems gracefully: Object.getOwnPropertyNames(this).forEach(property => {
const propertyValue = this[property];
delete this[property];
this[property] = propertyValue;
}); |
src/lib/parts.ts
Outdated
if (!this.endNode.isConnected && | ||
typeof customElements.upgrade === 'function') { | ||
document.adoptNode(fragment); | ||
customElements.upgrade(fragment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go this route, we need to polyfill on Safari.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might be inclined to polyfill TreeWalker
in ShadyDOM instead.
src/test/lib/render_test.ts
Outdated
}); | ||
|
||
test( | ||
'uses property setters in nested templates added after the initial render', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
duplicate test name?
Option two is basically what I implemented in lite-html. In my benchmarks the initialial load of my implementation is consistently faster, and the template processing is the largest component there. I haven't done a comprehensive comparison on code-size, but I think my implementation is both smaller and more performant (although that might be due to some optimizations I can make that are not possible with your architecture). If you want, I can look into the feasibility of porting my implementation to lit-html, and make a PR for it. It will require quite a bit of work since our AttributePart architecture is quite different, so I won't start with it unless you think it's a reasonable option. |
74465cd
to
ec3e98c
Compare
@sorvell PTAL Changed to call |
src/lib/template-instance.ts
Outdated
// Since we cloned in the polyfill case, now force an upgrade | ||
if (isCEPolyfill) { | ||
document.adoptNode(fragment); | ||
customElements.upgrade(fragment); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should only do this if it's not connected since otherwise it's duplicate work and crawling trees is costly. I think it's fine to merge this and just put a TODO here for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just fixed it here
This keeps us from creating instance properties that alias assessors on disconnected elements.
This technique only works if
customElements.upgrade
is implemented. It's in Chrome, the polyfill, and Safari TP, and Firefox nightly.There's two other ways we could solve this. First we either:
Then we go back to
document.importNode(template.content, true)
to clone & upgrade in one step.