-
Notifications
You must be signed in to change notification settings - Fork 166
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
Add polyfills for select ParentNode APIs. #389
Conversation
I need to figure out what to do about all of the tests that use @webcomponents/platform. It is ostensibly where the ParentNode polyfills would go, but we no longer vend it or any other way to get these polyfills outside of a complete bundle. For now, importing them directly from the other package's build output seems to work.
'querySelectorAll', | ||
'append', | ||
'prepend', | ||
'replaceChildren', |
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.
Was this the right thing to do here? I'm not totally sure what this list is about. There seems to be some stuff later in this file that implies that they're on the wrong prototype in older Safari and that this is just about putting them in the correct spot - should I consider doing this for ChildNode in #390 too?
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 think the concern was IE/Edge.
It would be good to verify (perhaps just via one-off manual testing rather than in the code itself) that these properties do not exist higher on the prototype chain than where we patch them on any browser. This would cause the patch to fail.
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 checked the earliest version of the browsers implementing append
(Edge 17, Firefox 49, Chrome 54, Safari 10) and they all have the descriptor on Document
, DocumentFragment
, and Element
prototypes but not the HTMLDocument
, HTMLElement
, or ShadowRoot
(if it exists) prototypes, so they should be alright assuming they haven't regressed and moved them around since.
Another issue regarding MutationObserver: these functions are meant to create one entry, but this implementation probably creates many. Is that something we care about? |
…tationObserver entries when inserting many nodes.
So following the spec more closely actually results in this being less work. The 'convert nodes into a node' algorithm basically just takes a list of nodes and puts them all in a fragment if there's not exactly one item, which can then be passed as one item to Shady DOM's |
// Implements 'convert nodes into a node'. | ||
// https://dom.spec.whatwg.org/#converting-nodes-into-a-node | ||
export const convertNodesIntoANode = (...args) => { | ||
if (args.length === 1) { |
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.
What if the only argument is a string? It won't get converted to a node in that case.
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.
Fix and add test?
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.
Good catch, should be fixed and tested now.
DocumentFragment.prototype, | ||
Element.prototype, | ||
]) { | ||
delete item.append; |
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.
Why is this needed?
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.
This and the others are here to remove the built-in implementations so that we can test it in browsers that actually do support it. I could also remove it if you think it's better to just run the tests against the built-in implementation, WDYT?
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.
OK, I missed the fact that this isn't a shadydom test.
</head> | ||
<body> | ||
<script> | ||
const testAppend = (createContainer) => { |
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.
It's simpler to keep the suite with the test functions. Let's get rid of this wrapper function. Same with other test files.
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.
Ok, I inlined these.
DocumentFragment.prototype, | ||
Element.prototype, | ||
]) { | ||
delete item.prepend; |
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.
Why is this needed?
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.
(replied in earlier comment)
</head> | ||
<body> | ||
<script> | ||
const testAppend = (createContainer) => { |
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.
testPrepend
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.
(Removed based on another comment in your review.)
<body> | ||
<script> | ||
const testAppend = (createContainer) => { | ||
test('Appends an element', () => { |
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.
These titles should say "Prepends"... same for all tests here.
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.
Fixed.
DocumentFragment.prototype, | ||
Element.prototype, | ||
]) { | ||
delete item.replaceChildren; |
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.
Why is this needed?
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.
(replied in earlier comment)
</head> | ||
<body> | ||
<script> | ||
const testAppend = (createContainer) => { |
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.
testReplaceWith
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.
(Removed based on another comment in your review.)
<body> | ||
<script> | ||
const testAppend = (createContainer) => { | ||
test('Appends an element', () => { |
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.
Titles of these tests should say "ReplaceWith"
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.
Fixed.
@@ -0,0 +1,37 @@ | |||
/** |
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.
Can you explain why these APIs are being added here rather than just in shadydom?
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.
This is to separate the polyfill for the feature itself from the part that adds support for the feature to Shady DOM. In this case (and for ChildNode), it was easier not to wrap the existing versions of these functions (built-in or polyfilled) since everything goes through Shady DOM's implementation of insertBefore
and removeChild
anyway, so Shady DOM doesn't actually use them. However, without them, we won't have support for these features without enabling Shady DOM.
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'm just not sure this is worth doing since there is no browser that has Shadow DOM but does not have ParentNode/ChildNode.
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 decided to check out caniuse.com and Chrome 53 is the only browser that has Shadow DOM v1 but not ParentNode. Should I remove these?
On that note, I wonder if it's time to drop Chrome 41 from the polyfill tests.
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 didn't realize that there was any browser that had this configuration. It seems ok then.
…n passing a single string.
'querySelectorAll', | ||
'append', | ||
'prepend', | ||
'replaceChildren', |
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 think the concern was IE/Edge.
It would be good to verify (perhaps just via one-off manual testing rather than in the code itself) that these properties do not exist higher on the prototype chain than where we patch them on any browser. This would cause the patch to fail.
packages/shadydom/src/utils.js
Outdated
// https://dom.spec.whatwg.org/#converting-nodes-into-a-node | ||
export const convertNodesIntoANode = (...args) => { | ||
if (args.length === 1) { | ||
return (typeof args[0] === 'string' ? document.createTextNode(args[0]) : args[0]); |
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.
Let's factor this out since it's done 2x?
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.
Ok, I moved it out. I also found that this expression doesn't exactly match what current browsers do so I updated it also. (AFAICT, the spec text for this doesn't say what happens to non-string, non-node values in this list but all browsers seem to just coerce to a string and make a text node from that string.)
DocumentFragment.prototype, | ||
Element.prototype, | ||
]) { | ||
delete item.append; |
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.
OK, I missed the fact that this isn't a shadydom test.
@@ -0,0 +1,37 @@ | |||
/** |
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'm just not sure this is worth doing since there is no browser that has Shadow DOM but does not have ParentNode/ChildNode.
…ow when trying to append a symbol.
packages/shadydom/src/utils.js
Outdated
* @return {!Node} | ||
*/ | ||
const convertIntoANode = (arg) => { | ||
return !(arg instanceof Node) ? document.createTextNode(String(arg)) : arg; |
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.
FYI, I removed this explicit conversion to string because browsers don't seem to do this and will throw when trying to append
a symbol.
Adds polyfills for
ParentNode
'sappend
,prepend
, andremoveChildren
functions and wrappers to support these in Shady DOM.