Skip to content
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

Merged
merged 24 commits into from
Oct 15, 2020
Merged

Add polyfills for select ParentNode APIs. #389

merged 24 commits into from
Oct 15, 2020

Conversation

bicknellr
Copy link
Collaborator

@bicknellr bicknellr commented Oct 7, 2020

Adds polyfills for ParentNode's append, prepend, and removeChildren functions and wrappers to support these in Shady DOM.

@bicknellr bicknellr marked this pull request as ready for review October 7, 2020 20:55
@bicknellr bicknellr requested a review from aomarks as a code owner October 7, 2020 20:55
@bicknellr bicknellr requested a review from sorvell October 7, 2020 20:55
Comment on lines +97 to +100
'querySelectorAll',
'append',
'prepend',
'replaceChildren',
Copy link
Collaborator Author

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?

Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

packages/shadydom/src/patches/ParentNode.js Outdated Show resolved Hide resolved
@bicknellr
Copy link
Collaborator Author

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.
@bicknellr
Copy link
Collaborator Author

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 insertBefore. This doesn't solve the multiple MutationObserver entries problem for replaceChildren though.

// Implements 'convert nodes into a node'.
// https://dom.spec.whatwg.org/#converting-nodes-into-a-node
export const convertNodesIntoANode = (...args) => {
if (args.length === 1) {
Copy link
Collaborator

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.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix and add test?

Copy link
Collaborator Author

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Collaborator Author

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?

Copy link
Collaborator

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) => {
Copy link
Collaborator

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.

Copy link
Collaborator Author

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Collaborator Author

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) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testPrepend

Copy link
Collaborator Author

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', () => {
Copy link
Collaborator

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.

Copy link
Collaborator Author

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;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this needed?

Copy link
Collaborator Author

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) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

testReplaceWith

Copy link
Collaborator Author

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', () => {
Copy link
Collaborator

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"

Copy link
Collaborator Author

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 @@
/**
Copy link
Collaborator

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?

Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

Copy link
Collaborator Author

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.

Copy link
Collaborator

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.

@bicknellr bicknellr requested a review from sorvell October 12, 2020 19:52
Comment on lines +97 to +100
'querySelectorAll',
'append',
'prepend',
'replaceChildren',
Copy link
Collaborator

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.

// 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]);
Copy link
Collaborator

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?

Copy link
Collaborator Author

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;
Copy link
Collaborator

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 @@
/**
Copy link
Collaborator

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.

@bicknellr bicknellr requested a review from sorvell October 15, 2020 00:18
* @return {!Node}
*/
const convertIntoANode = (arg) => {
return !(arg instanceof Node) ? document.createTextNode(String(arg)) : arg;
Copy link
Collaborator Author

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants