Re: [webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Dec 7, 2013, at 3:25 PM, Dominic Cooney domin...@google.com wrote: On Sat, Dec 7, 2013 at 10:06 AM, Ryosuke Niwa rn...@apple.com wrote: On Dec 6, 2013, at 5:01 PM, Ryosuke Niwa rn...@apple.com wrote: On Dec 6, 2013, at 1:20 AM, Brian Di Palma off...@gmail.com wrote: On Fri, Dec 6, 2013 at 3:24 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, Hopefully though they won't do that any longer in the ES6 module world. They had to be exposed on the global scope in some way otherwise they couldn't be used, in future that will no longer be the case. Are you proposing to provide some mechanism to declaratively define a custom element inside a module? How does a ES6 module end up having markup? I'll also point out that with our proposal to add an optional template argument, we could do: template id=myButton ... /template script (function () { class MyButton extends HTMLElement { ... } document.register('my-button', MyButton, document.getElementById('myButton')); )(); /script so authors DO have an option to hide the class entirely from the global scope. It's just not declarative. I don't think this proposal is an improvement over the document.register in the spec today. It is an improvement in that it reduces the boilerplate code that we expect many custom elements to have. The existing spec for document.register does not add a binding to the JavaScript scope. So it does not suffer the problem discussed in this thread. Sorry, I don't really understand what you mean by this. Could you clarify? Given that we don't want to change this or the global object per previous discussion in the working group, I don't know what discussion you are specifically referring to so my next statement is not agreeing or disagreeing with the preceding clause of this sentence. See Erik's inline comment in http://lists.w3.org/Archives/Public/public-webapps/2013AprJun/0122.html Unfortunately NodeJS broke this invariant already. `this` inside a module that has been required is a not the [[Global]] object. This has caused me a lot of personal porting pain so I agree we must not break this invariant on the web. I don't see how we can refer to a JS class/constructor declaratively. Yes. I can't think of an example where DOM attributes do this. onclick, etc. handlers relate to script, but they do not refer to specific objects. This is a problem with your proposal. I don't think this is an issue with our proposal. I don't think any proposal for declarative syntax can simultaneously satisfy requirements to not change the meaning of this inside the element definition and not pollute the global namespace at all. I think a proposal for declarative Custom Elements must also deal with the problems the group discovered when it last tried. They are summarized here: http://lists.w3.org/Archives/Public/public-webapps/2013JulSep/0287.html A lot of problems listed there appears to stem from an implicit assumption that the declarative syntax should have the same expressiveness as imperative API. I disagree with that proposition. Any moderately complicated Web apps will inevitably involve scripts. The existing Web APIs are designed around this principle; they address common use cases with declarative syntax and provide imperative APIs for more complicated use cases. - R. Niwa
Re: [webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Sat, Dec 7, 2013 at 1:01 AM, Ryosuke Niwa rn...@apple.com wrote: On Dec 6, 2013, at 1:20 AM, Brian Di Palma off...@gmail.com wrote: On Fri, Dec 6, 2013 at 3:24 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, Hopefully though they won't do that any longer in the ES6 module world. They had to be exposed on the global scope in some way otherwise they couldn't be used, in future that will no longer be the case. Are you proposing to provide some mechanism to declaratively define a custom element inside a module? How does a ES6 module end up having markup? It doesn't. I don't like mixing the different resource types inside one file. Whether that is a HTML file with JS inside it or a JS file with HTML inside it. I feel they should be kept separate from each other as much as possible. Especially since I have no need for the HTML markup in my ES6 module. The current document.register signature requires, TYPE, the custom element type of the element being registered PROTOTYPE, the custom element prototype, optional So I don't see what use the HTML markup would be to me. If we look at the proposal we are talking about here the signature has one extra parameter added, TEMPLATEELEMENT, HTMLTemplateElement used as template for custom element. again I'm not sure what I'd need the HTML markup for. You may point out that I need the HTMLTemplateElement, which is true and for that I'd really like to use a mechanism that as a proficient ES6+ developer I'd be quite familiar with. javascript import { myCustomElement } from my-customelement.html; class MyCustomElement extends HTMLElement { ... } document.register('my-customelement', MyCustomElement, myCustomElement); I think in fact that the import line can be made to work with the some tweaks to the standard module loader. I'd much prefer this over having a HTML file containing my code and business logic stuck inside an antiquated IIFE. With HTTP2.0/SPDY you can have your server push the CSS files related to the custom element so they are in cache when the element is created if browsers don't natively support the above code. I'd build a dependency tree by using the module loader imports so that any dependent custom elements are available. Actually I'm not sure I'd use HTML imports at all if I had this...I'm sure I'm missing some benefit they would provide? P.S. For extra fun you could import CSS in the same way and have it apply in scoped fashion to different elements. javascript import CSSStyleSheetObject from my-customelement.css apply to myCustomElement; import anotherCSSStyleSheetObject from my-application-styles.css apply to document; Once you have ES modules implemented this might be a quick addition for a browser maker. - R. Niwa
Re: [webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Sat, Dec 7, 2013 at 10:06 AM, Ryosuke Niwa rn...@apple.com wrote: On Dec 6, 2013, at 5:01 PM, Ryosuke Niwa rn...@apple.com wrote: On Dec 6, 2013, at 1:20 AM, Brian Di Palma off...@gmail.com wrote: On Fri, Dec 6, 2013 at 3:24 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, Hopefully though they won't do that any longer in the ES6 module world. They had to be exposed on the global scope in some way otherwise they couldn't be used, in future that will no longer be the case. Are you proposing to provide some mechanism to declaratively define a custom element inside a module? How does a ES6 module end up having markup? I'll also point out that with our proposal to add an optional template argument, we could do: template id=myButton ... /template script (function () { class MyButton extends HTMLElement { ... } document.register('my-button', MyButton, document.getElementById('myButton')); )(); /script so authors DO have an option to hide the class entirely from the global scope. It's just not declarative. I don't think this proposal is an improvement over the document.register in the spec today. Whether there is an argument for a template element is orthogonal to adding a binding to the JavaScript scope. The existing spec for document.register does not add a binding to the JavaScript scope. So it does not suffer the problem discussed in this thread. Given that we don't want to change this or the global object per previous discussion in the working group, I don't know what discussion you are specifically referring to so my next statement is not agreeing or disagreeing with the preceding clause of this sentence. I don't see how we can refer to a JS class/constructor declaratively. Yes. I can't think of an example where DOM attributes do this. onclick, etc. handlers relate to script, but they do not refer to specific objects. This is a problem with your proposal. I think a proposal for declarative Custom Elements must also deal with the problems the group discovered when it last tried. They are summarized here: http://lists.w3.org/Archives/Public/public-webapps/2013JulSep/0287.html Link provided for convenience, as you are no doubt aware of these. -- http://goto.google.com/dc-email-sla
Re: [webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Fri, Dec 6, 2013 at 3:24 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, Hopefully though they won't do that any longer in the ES6 module world. They had to be exposed on the global scope in some way otherwise they couldn't be used, in future that will no longer be the case. and authors could use document.register to avoid that altogether if they really wanted. - R. Niwa
Re: [webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Dec 6, 2013, at 1:20 AM, Brian Di Palma off...@gmail.com wrote: On Fri, Dec 6, 2013 at 3:24 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, Hopefully though they won't do that any longer in the ES6 module world. They had to be exposed on the global scope in some way otherwise they couldn't be used, in future that will no longer be the case. Are you proposing to provide some mechanism to declaratively define a custom element inside a module? How does a ES6 module end up having markup? - R. Niwa
Re: [webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Dec 6, 2013, at 5:01 PM, Ryosuke Niwa rn...@apple.com wrote: On Dec 6, 2013, at 1:20 AM, Brian Di Palma off...@gmail.com wrote: On Fri, Dec 6, 2013 at 3:24 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, Hopefully though they won't do that any longer in the ES6 module world. They had to be exposed on the global scope in some way otherwise they couldn't be used, in future that will no longer be the case. Are you proposing to provide some mechanism to declaratively define a custom element inside a module? How does a ES6 module end up having markup? I'll also point out that with our proposal to add an optional template argument, we could do: template id=myButton ... /template script (function () { class MyButton extends HTMLElement { ... } document.register('my-button', MyButton, document.getElementById('myButton')); )(); /script so authors DO have an option to hide the class entirely from the global scope. It's just not declarative. Given that we don't want to change this or the global object per previous discussion in the working group, I don't see how we can refer to a JS class/constructor declaratively. - R. Niwa
[webcomponents] Binding Custom Element without Polluting Global Scope (Was Proposal for Cross Origin Use Case and Declarative Syntax)
On Nov 12, 2013, at 12:45 AM, Ryosuke Niwa rn...@apple.com wrote: On Nov 12, 2013, at 8:12 AM, Dimitri Glazkov dglaz...@chromium.org wrote: 1) It is not friendly to ES6 classes. In fact, you can't use class syntax and this syntax together. Okay, let the author define the constructor. 3) The approach pollutes global name space with constructors. This had been voiced many times as unacceptable by developers. We can solve this problem by using JavaScript object path as opposed to a variable name. So instead of: template register=my-button interface=MyButton /template We allow: script var my = {views:{MyButton: ~}}; /script template register=my-button interface=my.views.MyButton /template While this requires some variable to be exposed on the global scope, libraries and frameworks do this already, and authors could use document.register to avoid that altogether if they really wanted. - R. Niwa