-
Notifications
You must be signed in to change notification settings - Fork 3.9k
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 DOM v1 #7059
Shadow DOM v1 #7059
Conversation
Thanks for your pull request. It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA). 📝 Please visit https://cla.developers.google.com/ to sign. Once you've signed, please reply here (e.g.
|
I signed it! Company name: Marfeel Solutions SL |
CLAs look good, thanks! |
} | ||
|
||
function areNativeCustomElementsSupported() { | ||
return isNative(win.document.registerElement) || isNative(win.customElements && win.customElements.define); |
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.
iOS never had registerElement
, so we can skip isNative(registerElement)
.
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.
But if the polyfill is loaded before this class, document.registerElement will exist, right? That why we need to check that it exists and is browser native.
You are right that checking for Custom Elements v1 does not make sense.
*/ | ||
let shadowDomMethod; | ||
|
||
let win = window; |
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.
Unfortunately we can't have window-dependent side effects in our source code. Further getShadowDomMethod().call(...)
might have issues if resolved via win.Element
because we also allow most of APIs to be called from friendly iframes.
What I'm thinking instead, maybe we could try to have a string var: shadowDomSupport
. It could have values none
, v0
and v1
. This way we can set this value from tests and try different code paths.
In that case, isShadowDomSupported() {return shadowDomSupport != 'none'}
. And we could switch getShadowDomMethod()
to something like this:
createShadowRoot(host) {
switch(getShadowDomSupport()) {
case 'v0':
return host.createShadowRoot();
case 'v1':
return host.attachShadow({...});
}
assert(...);
}
*/ | ||
export function isShadowDomSupported() { | ||
if (shadowDomSupported === undefined) { | ||
shadowDomSupported = !!getShadowDomMethod() && areNativeCustomElementsSupported(); |
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.
Please add TODO:
TODO: Remove native CE check once WebReflection/document-register-element#96 is fixed.
}); | ||
}); | ||
}); | ||
}); |
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.
nit: trailing new line.
*/ | ||
export function getShadowDomMethod() { | ||
if (shadowDomMethod === undefined) { | ||
shadowDomMethod = win.Element.prototype.createShadowRoot || win.Element.prototype.attachShadow; |
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'd say let's pull the trigger and make attachShadow
(v1) the preferred way if both available.
@oliverfernandez Thanks a lot! This looks great! Just a couple of comments. |
@dvoytenko I did all the changes you suggested. However, I think that we need to keep checking for native support of document.registerElement, to check that it has not been polyfilled |
}; | ||
|
||
/** | ||
* @type {string|undefined} |
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.
{ShadowDomVersion|undefined}
let shadowDomSupportedVersion; | ||
|
||
/** | ||
* @param {string|undefined} val |
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.
{ShadowDomVersion|undefined}
|
||
/** | ||
* Returns the supported version of Shadow DOM spec. | ||
* @param {function=} optional for testing |
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.
Name is missing for @param
- the compiler errors out on this in travis. Also, this is element class, right? Maybe let's call it opt_elementClass
instead?
} | ||
|
||
function areNativeCustomElementsSupported() { | ||
return isNative(self.document.registerElement); |
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.
No, I meant we should actually only do the other one: isNative(self.customElements && self.customElements.define)
. Unless I misunderstood. But basically on iOS Safari, isNative(self.document.registerElement)
will always be false
, right?
However, there's still a problem. For some reason the polyfill overrides the existing the native CustomElementRegistry
and so, event isNative(self.customElements.define)
will always be false
:(. We are getting a good traction on fixing the original issue though, but I don't know ETA yet.
The only way I found to determine this correctly is by running this code:
isNative(self.Object.getOwnPropertyDescriptor(self, 'customElements').get)
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, got it.
The only drawback then will be that old Chrome versions, which only support Custom Elements v0, won't use native Shadow DOM. Are we ok with this?
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 point. We could certainly also check for registerElement
. Could you please take a look if polyfill overrides it as well? If it's too much trouble, we can move with this version, though.
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.
Yes, will do.
By the way, does self.Object.getOwnPropertyDescriptor(self, 'customElements').get
works for you in Chrome? I always get undefined
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 undefined
because of the polyfill. It always overrides customElement
with the direct value. The native implementation, on the opposite, provides a getter and it's defined. So, in theory, we could simply check whether getter is present on not - but that feels too rigid to me.
Either way it's too rigid, but this way could get us going long enough for the original polyfill issue to be fixed and we'll be able to remove isNative check completely :)
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've tested in several devices, and in Chrome 55 self.Object.getOwnPropertyDescriptor(self, 'customElements').get
always returns undefined
, no matter if the polyfill is present or not. However, in Canary or Safari Tech Preview it behaves as you described. It's like customElements implementation in Chrome 55 is not providing the getter.
In any case, since document.registerElement
is not overridden by the polyfill, I'll fix this by checking both document.registerElement
or self.Object.getOwnPropertyDescriptor(self, 'customElements').get
.
Working on it right 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.
Thanks a lot!
@oliverfernandez Cool. This is very close. I asked a couple more updates. A more serious one - is still an issue with native-vs-non-native detection. I think I found a way to detect that. See comments on that above. Thanks a lot! |
Checks again for CE v0 so we don't disable native Shadow DOM in browsers that don't support CE v1
@dvoytenko All changes applied, but I think I'm going to need some help in order Closure Compiler to accept Element.prototype.attachShadow |
if (isShadowDomSupported()) { | ||
const shadowDomSupported = getShadowDomSupportedVersion(); | ||
if (shadowDomSupported == ShadowDomVersion.V1) { | ||
return hostElement.attachShadow({mode: 'open'}); |
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.
So, yeah, attachShadow
looks to be absent is externs :(
Please try to add this to shadow_dom.js:
/**
* @see https://www.w3.org/TR/shadow-dom/#idl-def-ShadowRootInit
* @typedef {{
* mode: string
* }}
*/
var ShadowRootInit;
/**
* @see https://www.w3.org/TR/shadow-dom/#h-extensions-to-element-interface
* @param {ShadowRootInit=} opt_init
* @return {!ShadowRoot}
*/
Element.prototype.attachShadow = function(opt_init) {};
This should do it.
@oliverfernandez Thanks! All looks good. We just need, as you said, add |
@dvoytenko I think we got it :) |
Merged. Thanks a lot, @oliverfernandez! We also did it on the eve of Safari 10.1 release with native CE support :) |
@dvoytenko And I think it gets even better! iOS 10.3 beta has been released today too, and I think it includes the updated Safari too. I'm checking it |
* Shadow DOM v1 API support * Removed unintended code comment * PR fixes Gives preference to Shadow DOM v1 over v0 * Fixed lint errors * Fixes to closure-compiler errors Checks again for CE v0 so we don't disable native Shadow DOM in browsers that don't support CE v1 * Fix closure compiler error * Added Shadow DOM v1 spec to Closure Compiler
* Shadow DOM v1 API support * Removed unintended code comment * PR fixes Gives preference to Shadow DOM v1 over v0 * Fixed lint errors * Fixes to closure-compiler errors Checks again for CE v0 so we don't disable native Shadow DOM in browsers that don't support CE v1 * Fix closure compiler error * Added Shadow DOM v1 spec to Closure Compiler
Support for Shadow DOM v1 in AMP Shadow
To cover cases like Safari 10, where Shadow DOM is implemented but Custom Elements is not, native Shadow DOM is disabled because Custom Elements polyfill does not cover custom elements inside shadow roots
Related to #6893