WICG / webcomponents

Web Components specifications
Other
4.39k stars 376 forks source link

Non-class based example of customElement.define() #587

Closed rektide closed 8 years ago

rektide commented 8 years ago

Hello, I'd like for there to be an available, working examples of autonomous and customized Custom Elements made without use of the class syntax. The Mozilla MDN page for example shows a use of Object.create(HTMLElement.prototype) to create an autonomous custom element on it's Custom Elements page that satisfies this non-class based way of working, however that example doesn't work- it yields Uncaught TypeError: Failed to execute 'define' on 'CustomElementRegistry': The callback provided as parameter 2 is not a function. on customElement.define("my-tag", MyTag).

What is a valid syntax to use now, for creating autonomous and customized Custom Elements? Might we add some examples of such in to the spec?

domenic commented 8 years ago

It's not possible to use custom elements without ES6 classes. That was a design decision necessary to achieve consensus at the January face-to-face meeting.

Closing, since there's nothing actionable here, but happy to continue discussing in the closed thread.

domenic commented 8 years ago

I've updated the linked documentation to at least be up to date with custom elements v1. It still is on old shadow DOM however, and in general https://developer.mozilla.org/en-US/docs/Web/Web_Components looks very, very outdated and confusing. If anyone has time to update all the web components docs to the latest specs, that would be a great help to developers everywhere, I am sure.

rektide commented 8 years ago

I'd like to see non-class based JS become possible, hopefully in v2. Please re-open this as a request. Classes are syntax, statically constructed, which means we can't create components on the fly with code. This is a serious and frankly scary limitation.

For an example of use, if I wanted to generate components for, say, schema.org, the class based syntax means that I have to manually type out class definitions for ~650 components. Having normal, regular JS objects would have let me use code to generate new components. Please re-open this as an outstanding issue @domenic.

domenic commented 8 years ago

Sorry, this was a condition of getting consensus, and is now fully built in to the architecture of the feature. It cannot be changed.

domenic commented 8 years ago

I hope you're aware that you can generate classes dynamically just as easily as functions, so you certainly would not need to type those out. Classes are just as much syntax as functions are. If you don't know how do do this, please ask on StackOverflow, but not here.

rniwa commented 8 years ago

FWIW, you can use Reflect.construct to call HTMLElement's constructor. e.g.

function CustomElement() {
    return Reflect.construct(HTMLElement, [], CustomElement);
}
Object.setPrototypeOf(CustomElement.prototype, HTMLElement.prototype);
Object.setPrototypeOf(CustomElement, HTMLElement);

customElements.define('custom-element', CustomElement);
Mr0grog commented 8 years ago

(Apologies if this issue has already been discussed elsewhere; I had entirely failed to consider it before and I haven’t seen it mentioned…)

Will this cause problems for existing JS codebases that use a WebComponents polyfill with a transpiler like Babel? For example, transpiling this code using Babel’s es2015 preset fails to work because the resulting JS doesn’t use Reflect.construct:

class TestElement extends HTMLElement {
  constructor () {
    console.log('Constructin’');
    super();
  }
  connectedCallback () {
    console.log('Connectin’');
  }
  disconnectedCallback () {
    console.log('Disconnectin’');
  }
}

customElements.define('test-element', TestElement);

const testInstance = document.createElement('test-element');
document.body.appendChild(testInstance);

I understand that native custom elements won’t be available in browsers that don’t already support ES-2015 class syntax, but if someone is using Babel + a polyfill for web components, it seems like they’d have a situation where their code works in older browsers (because the polyfill is active), but not in newer ones (because the polyfill just defers to the native implementation). That seems like a pretty big practical problem, but is it one you are concerned about here?

rniwa commented 8 years ago

It is true that if you're using Babel and polyfill, then the above code won't work out-of-box but that's true of any polyfill that got written before the standard is finalized.

There are various ways to workaround such issues, and probably the simplest solution is to wrap the thing you pass to customElements.define with a class. e.g.

function defineCustomElementInBabel(name, legacyConstructor) {
    var wrapperClass = class extends legacyConstructor {
        constructor() {
            var newElement = new Reflect.construct(HTMLElement, [], wrapperClass);
            legacyConstructor.call(newElement);
            return newElement;
        }
    };
    customElements.define(name, wrapperClass);
}

Obviously, this leaves new TestElement non-functional. An alternative approach is to replace super() call in TestElement by something special like:

class TestElement extends HTMLElement {
    constructor () {
        constructCustomElement(TestElement);
    }

with

function constructCustomElement(newTarget) {
        Reflect.construct(HTMLElement, [], newTarget);
}

There are dozens of other ways to cope with this limitations and that's really up to framework and library authors.

On a broader note, I don't think the standards process or API design in standards should be constrained by polyfills written before the general consensus on the API shape has been reached and at least two major browser engines have implemented it. Also, deploying a polyfill on production before the standards have become stable is almost always a bad idea.

Mr0grog commented 8 years ago

It is true that if you're using Babel and polyfill, then the above code won't work out-of-box but that's true of any polyfill that got written before the standard is finalized.

I suppose I was really most focused here on the impact to existing codebases. It’s not as if that hasn’t been a consideration in other web standards, though I do understand that current usage of polyfills for custom elements (and especially v1-esque polyfills) is quite small.

On the other hand, there is a lot of Babel usage out there (the majority of non-trivial JS codebases I’ve worked on as a consultant over the past year have used it), and I hadn’t really expected that I’d need such an awkward and specialized method for creating a custom element with it. It may be further complicated in trying to find solutions that allow someone to inherit from a custom element provided as a third-party module, where the provider of the component may have solved the issue in their own way. As you noted, there are many ways to work around it.

Also, deploying a polyfill on production before the standards have become stable is almost always a bad idea.

I agree! I’ve just spent a lot of time shaking my head at bugs I’ve had to fix for clients because they shipped code that depends on an alpha/beta version of a library or a polyfill for a standard that hasn’t been finalized yet, so I’m sensitive to these kinds of decisions.

At the end of the day, I’m just a little frustrated at realizing the API for custom elements is less friendly than I had thought (again, entirely my fault for not reading as closely as I should have). I also understand that this is well past the point where anyone is willing to rethink it.

(I also want to be clear that I really appreciate the work being done here by everyone on the working group. Obviously I would have liked this issue to turn out differently, but I’m not complaining that this is some horrible travesty. The big picture is still an improvement for the web.)

rniwa commented 8 years ago

On the other hand, there is a lot of Babel usage out there (the majority of non-trivial JS codebases I’ve worked on as a consultant over the past year have used it), and I hadn’t really expected that I’d need such an awkward and specialized method for creating a custom element with it.

Okay. If you don't like a method, you can also define a specialized super class shown below. Obviously, this particular version of BabelHTMLElement only works with a browser engine with both ES6 and custom elements support but you can make it work with whatever polyfill as well.

function BabelHTMLElement()
{
  const newTarget = this.__proto__.constructor;
  return Reflect.construct(HTMLElement, [], newTarget);
}
Object.setPrototypeOf(BabelHTMLElement, HTMLElement);
Object.setPrototypeOf(BabelHTMLElement.prototype, HTMLElement.prototype);

class MyElement extends BabelHTMLElement {
  constructor() {
    super();
    this._id = 1;
  }
}

customElements.define('my-element', MyElement);
rniwa commented 8 years ago

Note that you can be more sleek with something like this (although I highly discourage you to override the native HTMLElement interface like this but sooner or later someone is gonna realize and do it so I'm gonna leave it here).

HTMLElement = (function (OriginalHTMLElement) {
  function BabelHTMLElement()
  {
    if (typeof Reflect == 'undefined' || typeof Reflect.construct != 'function' || typeof customElements == 'undefined') {
      // Use your favorite polyfill.
    }
    const newTarget = this.__proto__.constructor;
    return Reflect.construct(OriginalHTMLElement, [], newTarget);
  }
  Object.setPrototypeOf(BabelHTMLElement, OriginalHTMLElement);
  Object.setPrototypeOf(BabelHTMLElement.prototype, OriginalHTMLElement.prototype);
  return BabelHTMLElement;
})(HTMLElement);

class MyElement extends HTMLElement {
  constructor() {
    super();
    this._id = 1;
  }
}

customElements.define('my-element', MyElement);
rniwa commented 8 years ago

@WebReflection: In the case, you're still looking for a solution that works in both Babel + Polyfill and native ES6 + custom elements, see the comment above ^

WebReflection commented 8 years ago

@rniwa thanks for mentioning me but I'm not sure it's so easy.

Babel is plain broken when it comes to super calls and my poly already patches HTMLELement, so does the one from googlers.

I strongly believe this should be solved on Babel side, otherwise we're blocking and degrading native performance because of tooling on our way.

Tooling should improve and help, not be a problem.

rniwa commented 8 years ago

I've verified that both the ES6 and the Babel transpiled version works. The key here is to directly invoke Reflect.construct in your polyfill and not rely on Babel's super() call which, as you pointed out, is broken.

WebReflection commented 8 years ago

I'll play with your implementation and see how it goes. Maybe it'll make ife easier for everyone in this way so ... why not.

Thanks.

WebReflection commented 8 years ago

@rniwa it takes just new MyElement(); to fail with an illegal constructor error and the problem with babel is that even if you have that this._id set during constructor invokation, any other method defined in the class won't be inherited so no, your one does not seem to be a solution.

To summarize the issue:

class List extends Array {
  constructor() {
    super();
    this._id = 1;
  }
  method() {}
}

console.log((new List).method); // undefined

It doesn't matter if you have set something in the constructor if everything else is unusable

edit: in your case just add a method to your MyElement class and try to use it, it won't be there

rniwa commented 8 years ago

Oh, I see, that's just broken. Babel needs to fix that.

justinfagnani commented 8 years ago

@rniwa just sent me to this issue. I'd like to share some of what we've done on the polyfill side of things...

First, we have a "native shim" to the Custom Elements polyfill so that ES5 constructors can be used to implement elements. There have been two versions of this shim:

The first version patched window.HTMLElement as a constructor function that used Reflect.construct along with this.constructor to emulate new.target. This has some prohibitive performance issues because 1) Reflect.construct is slow and 2) Reflect.construct isn't a real substitute for super() as it always creates a new instance, so this new HTMLElement constructor would always throw away the currently initializing instance and return a new Element instance. (old version: https://github.com/webcomponents/custom-elements/blob/b43236a7da0917ea938b6cb1aa3116caaeb6e151/src/native-shim.js )

The new version patches up the CustomElementRegistry API to generate a stand-in class at define() time and define that, and then keep it's own registry of user-defined ES5 constructors. It then does some shuffling for initialization. This approach is much faster and incurs only a 10% overhead over native CEs. The new version is here: https://github.com/webcomponents/custom-elements/blob/master/src/native-shim.js

There are some caveats that I list in the comments of the shim:

  1. All constructors in a inheritance hierarchy must be ES5-style, so that they can be called with Function.call(). This effectively means that the whole application must be compiled to ES5.
  2. Constructors must return the value of the emulated super() call. Like return SuperClass.call(this)
  3. The this reference should not be used before the emulated super() call just like this is illegal to use before super() in ES6.
  4. Constructors should not create other custom elements before the emulated super() call. This is the same restriction as with native custom elements.

1) is a restriction because ES5 constructors cannot emulate super() and call into an ES6 constructor. 2) is just making ES5 constructors slightly more spec-compliant with ES6 constructors and required because HTMLElement sometimes returns an object other than this. I've worked with the major compilers to get their class transformations to implement this properly. Babel already worked. TypeScript has just fixed this, and Closure's fix is in review now. 3) is just respected the TDZ for this even in ES5 constructors. This shouldn't be something that authors need to care about if they write ES6. 4) is the same restriction that native CEs have.

What this means for Custom Elements authors is that everyone should write and distribute ES6 classes and let applications do any compiling down to ES5 that they need. This is a little different than the current norm of writing in ES6 and distributing ES5, but it will be necessary for any libraries that extend built-ins - Custom Elements aren't really unique here. Apps can either send ES5 to older browsers and ES6 to newer browser, or ES5 to everything using the shim.

WebReflection commented 8 years ago

Object.setPrototypeOf(this, elementProto) per each custom elements is just 10% slower?

Because I've proposed that already in the related Babel bug (since Babel is bugged for this and every other native constructor call) and they told me they didn't want to lose performance.

It looks like they delegated to you their transformation problem I've already said how to solve.

Thanks for sharing anyway, but I'm not sure this is the right way to go.

trusktr commented 7 years ago

First, ES6 classes have a ugly static limitations (permanently engrained super references), and now we can't use ES5 classes in custom elements? What if we generate those classes from a class library? This is not ideal. The following should NOT give an error:

function BarBar() { HTMLElement.call(this); console.log('hello'); }
BarBar.prototype = Object.create(HTMLElement.prototype)
customElements.define('bar-bar', BarBar)
document.createElement('bar-bar')

Output:

Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function.

and

function BarBar() { var _this = new HTMLElement(); console.log('hello'); return _this }
BarBar.prototype = Object.create(HTMLElement.prototype)
customElements.define('bar-bar', BarBar)
document.createElement('bar-bar')

output:

Uncaught TypeError: Illegal constructor

and

function BarBar() { var _this = new HTMLElement(); console.log('hello'); return _this; }
BarBar.prototype = Object.create(HTMLElement.prototype)
customElements.define('bar-bar', BarBar)
document.createElement('bar-bar')

output:

Uncaught TypeError: Illegal constructor

Honestly, why?

trusktr commented 7 years ago

Why is the web becoming inflexible? Why are we blocking the dynamic nature of pre-ES6?

rniwa commented 7 years ago

This is not about Web becoming inflexible. This is about using [NewTarget] internal slot. new HTMLElement doesn't work because localName cannot be determined inside HTMLElement's constructor.

I've made a number of suggestions to solve this problem, one of which was about passing the local name from createElement, custom element's constructor, and then to HTMLElement. In this world, we can do the reverse lookup from the local name to the constructor object, and construct the element. However, this approach allows an inconsistency between the the actual constructor of HTMLElement's constructor and what HTMLElement's constructor ends up creating. Furthermore, it requires the HTMLElement's constructor to be called with the local name as an argument, which many people argued are unnecessary and ugly. Optionally allowing this would mean that the behavior of HTMLElement's constructor would flip between two modes, which is also not ideal.

trusktr commented 7 years ago

I feel like it may be a bad design for the localName string property to be coupled to specific semantics of the JavaScript language. I like that you tried to fix the problem; it would allow the end user of the API to pass in any valid JavaScript class, not just ES6 classes and I think that would be very beneficial because not everyone wants to use ES6 classes all the time.

Furthermore, it requires the HTMLElement's constructor to be called with the local name as an argument, which many people argued are unnecessary and ugly.

Definitely true, that would be ugly!

If I understand correctly, new.target doesn't work with ES5 classes because calling a super constructor in the form SuperConstructor.call(this) means that there won't be a new.target reference inside SuperConstructor, so when HTMLElement is used like that it won't have a new.target and therefore cannot look up the constructor in the custom element registry?

Maybe we can add something to JavaScript? What if we add a new method to functions similar to Reflect.construct and that takes a context object, and only works when the containing constructor is called with new.

function Foo(...args) {
  HTMLElement.construct(this, args) // or similar, and new.target in HTMLElement is Foo.
}

Foo.prototype = Object.create(HTMLElement.prototype)

customElements.define('x-foo', Foo)
new Foo
trusktr commented 7 years ago

Aha!! I got it to work with ES5 classes using Reflect.construct! Try this in console:

function Bar() {
  console.log('Bar, new.target:', new.target)
  let _ = Reflect.construct(HTMLElement, [], new.target)
  _.punctuation = '!'
  return _
}

Bar.prototype = Object.create(HTMLElement.prototype)

function Baz() {
  console.log('Baz, new.target:', new.target)
  let _ = Reflect.construct(Bar, [], new.target)
  return _
}

Baz.prototype = Object.create(Bar.prototype)

Baz.prototype.sayHello = function() {
  return `Hello ${this.localName}${this.punctuation}`
}

customElements.define('x-baz', Baz)

const baz = new Baz

console.log(baz.sayHello())

And this inside the Baz.prototype.sayHello is as expected! So, problem solved! I am HAPPY! One just has to use that Reflect.construct pattern, and inside a constructor manipulate _ instead of this, which I don't mind doing. A downside is that it creates a wasteful object on instantiation because this isn't being used and then will get GCed after the constructor returns _, so double the object creation.

rniwa commented 7 years ago

If you can use Reflect.construct, just do that. I’ve stated it in https://github.com/w3c/webcomponents/issues/587#issuecomment-254017839.

Please go read the discussions above before adding a new comment.

trusktr commented 7 years ago

Oops, you're right, but also to note that I'm using new.target which is important if the class hierarchy is deeper. Sorry! And Thanks!

Giwayume commented 7 years ago

Honestly all of these workarounds just make me not want to write web components. You're not doing a very good job at selling this technology. "Oh no, it would be inconvenient for the browser vendor to implement" is not a valid excuse.

klarkc commented 7 years ago

@trusktr this kind of workaround must not exist in a standard, it's too messy. Also forcing the developers to use only es6 classes will throw a lot of potential web components adopters to other technologies and frameworks, turning the main objective of web components not reachable...

rniwa commented 7 years ago

Again, you can just use Reflect.construct to make it work with non-class constructors. See https://github.com/w3c/webcomponents/issues/587#issuecomment-254017839. In addition, Safari, Firefox, and Chrome all have been shipping with class syntax for more than a year.

SerkanSipahi commented 7 years ago

@klarkc @Giwayume this look not messy -> https://github.com/WebReflection/classtrophobic/#classtrophobic-

Giwayume commented 7 years ago

@SerkanSipahi This is about the natural language. The idea of web components is that they're universal and you don't have to install a bunch of 3rd party dependencies a page to get them to "just work".

puppetmaster3 commented 7 years ago

Each of us users now has to babel. (ex: https://stackoverflow.com/questions/43287186/why-is-wecomponentsjs-custom-elements-es5-adapter-js-not-working )

Why would you or someone not distribute the es5 version of the needed .js libraries, such as components and shadow so that part is done for us? We would then just need to babel the acctual component, not the dependencies done N times, one per each remote project that uses standard components.

lexigren commented 7 years ago

@rniwa thanks for es5 extending example with Reflect.construct, I was already going to abandon idea to use webcomponents to refactor messy legacy vanillajs/jq code.

trusktr commented 7 years ago

@rniwa Simply using Reflect.construct doesn't solve problems.

Reflect.construct is available only in Edge 12+! That's a big (bad) deal because we need to support older systems through polyfills that can't be polyfilled properly, and Custom Elements v1 is relying on not-completely-polyfillable requirements in a day and age when we need it to be 100% polyfillable to make everyone's lives easier.

The strict enforcement of using new means that transpilers can not compile to ES5 without using Reflect.construct because Reflect.construct won't work in anything below Edge 12.

This is a bad because not everyone is off of IE 10 or 11 yet, and there's no way to transpile this to a format that doesn't use new.target or Reflect.construct.

What this means is that people transpiling this to ES5 and using a Custom Elements v1 and Reflect polyfills will get lucky that it works in IE10, but then they'll get the following error in new browsers like Chrome:

Uncaught TypeError: Failed to construct 'HTMLElement': Please use the 'new' operator, this DOM object constructor cannot be called as a function

For example, see how bad this is with [Buble output](https://buble.surge.sh/#class%20FooBar%20extends%20HTMLElement%20%7B%0A%20%20constructor()%20%7B%0A%20%20%20%20super()%0A%20%20%20%20console.log('foo-bar')%0A%20%20%7D%0A%7D%0A%0AcustomElements.define('foo-bar'%2C%20FooBar)%0A%0Anew%20FooBar). Run the output code in Chrome.

This is not good! It makes things very difficult, especially in a time when many people still have to support non-native-ES2015+ environments.


Sorry for posting this twice, I wanted everyone to see it.

trusktr commented 7 years ago

Buble is "batteries included", meaning I can't configure it to use Reflect.construct only for certain envs like I probably can with babel-preset-env, which means I'd have to switch to Babel, then I'd have to start making multiple builds, which will get very ugly for library authoring.

trusktr commented 7 years ago

Aha, I know what the best solution is (thought it's not that good):

I can tell app developers: if you want to register my Custom Elements, you need to detect the user's browser, then use document.registerElement in IE (with polyfill), otherwise you can likely use customElements.define in all the other browsers (including Edge) because they support Reflect.construct.

Now, that's uuugly!

trusktr commented 7 years ago

The reason I'm having this problem is because I'm writing classes that I can use with Custom Elements v1 using constructors, but I need to support older browsers that don't have Reflect.construct, so I'm writing classes that work when registered with v0 or v1 (this seems like a reasonable thing for a Custom Element library author to want).

justinfagnani commented 7 years ago

@trusktr this problem is why we created the custom-elements-es5-adapterjs, that I've mentioned here before: https://github.com/webcomponents/webcomponentsjs#custom-elements-es5-adapterjs

trusktr commented 7 years ago

Wow Justin, that's an incredible hack (using Object.setPrototypeOf(this, ...) inside the native constructor. I hadn't thought of such a thing before.

The arrow function, const, and Map is still in the way though. If we're running this code in older browsers (which is probably true if we're compiling to ES5), it will throw a syntax error.

Luckily for me, I'm supporting IE11+, so I only need to change to non-arrow.

justinfagnani commented 7 years ago

The shim is intended to be run on browsers with native Custom Elements, to allow ES5 elements. On other browsers just use the polyfill.

trusktr commented 7 years ago

To make things easy for people (f.e. people learning HTML and barely JavaScript), things just needs to work without complications. As such, I will include this adapter in my library so that things are simply easy.

(I'm not saying it's ideal from a technical standpoint of manageability and flexibility, just that in most cases it is easier to just ship polyfills for end users, especially if the polyfill does nothing if the thing being polyfilled already exists).

I'm not a fan of telling people "hey, you're running in IE, use this, this, this, this, this, and this polyfill". That can be somewhat annoying for people, and sometimes turns them away from simply trying something they otherwise might've liked.

It's like page load times: if the page takes too long to load, people may just leave a site that they might've otherwise liked; the same concept.

trusktr commented 7 years ago

What will this do in older browsers that have a window.customElements polyfill? Hmmm, also class syntax will trip IE11.

What's your recommendation for libs then? I don't want to tell people: "detect the browser on server side and send the script tag if needed" for example. I want to tell people, regardless of browser, "use this script tag for my library" and done.

Jeff17Robbins commented 7 years ago

In case this is helpful, we are detecting the browser and dynamically loading the right libraries based on the browser. We do it inside our library so our users don't have to see that.

But instead of rolling your own dynamic loading, you could instead use https://github.com/webcomponents/webcomponentsjs#webcomponents-loaderjs. This does dynamic loading for you.

Best, Jeff Robbins

On Sat, Sep 30, 2017 at 3:01 PM Joe Pea notifications@github.com wrote:

What will this do in older browsers that have a window.customElements polyfill? Hmmm, also class syntax will trip IE11.

What's your recommendation for libs then? I don't want to tell people: "detect browser on server side and send the script tag if needed" for example. I want to tell people, regardless of browser, "use this script tag for my library" and done.

— You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/w3c/webcomponents/issues/587#issuecomment-333328992, or mute the thread https://github.com/notifications/unsubscribe-auth/ACAWh_k8NlA5nTzLyJyxZf7QbZgUq1rLks5sno_zgaJpZM4KXuh2 .

robdodson commented 7 years ago

Here's the funkiness I used on a recent angular + custom elements project to conditionally load the custom-elements-adapter. angular-cli will use webpack to dynamically inject polyfills at the end of your index.html, so that's how I load webcomponents.js after this bit has had a chance to run. Frankly it's not awesome, but it may be something that we can put into a webpack plugin so devs don't have to muck with it much :\

trusktr commented 7 years ago

@robdodson that's an interesting trick. I did something else: I changed arrows to functions, and put the class definition inside an eval() and it worked that way without causing syntax errors.

But I have another problem: Apparently this all works great with Babel's ES5 output, but I get errors with Buble's ES5 output (I'm using Buble to transpile my lib). I decided not to muck with it for now and support Edge 13+, and maybe by the time the lib I'm making is actually ready for anything serious this adapter won't be needed anymore! 😆

robdodson commented 7 years ago

I'm not sure if this is true but you might check to see if eval'ing the class like that fails in a CSP environment.

On Sat, Sep 30, 2017, 10:27 PM Joe Pea notifications@github.com wrote:

@robdodson https://github.com/robdodson that's an interesting trick. I did something else: I changed arrows to functions, and put the class definition inside an eval() and it worked that way without causing syntax errors.

But I have another problem: Apparently this all works great with Babel's ES5 output, but I get errors with Buble's ES5 output (I'm using Buble to transpile my lib). I decided not to muck with it for now and support Edge 13+, and maybe by the time the lib I'm making is actually ready for anything serious this adapter won't be needed anymore! 😆

— You are receiving this because you were mentioned.

Reply to this email directly, view it on GitHub https://github.com/w3c/webcomponents/issues/587#issuecomment-333354673, or mute the thread https://github.com/notifications/unsubscribe-auth/ABBFDdr_smTZqmKu64nKbdcp4sNsuqZoks5snyK0gaJpZM4KXuh2 .

WebReflection commented 7 years ago

Wow Justin, that's an incredible hack (using Object.setPrototypeOf(this, ...) inside the native constructor. I hadn't thought of such a thing before.

you were worried about Edge 12+, setPrototypeOf can't be polyfilled in IE < 11.

Anyway, the issue has been addressed and solved for Babel ages ago, without needing extra files. https://github.com/WebReflection/babel-plugin-transform-builtin-classes

trusktr commented 7 years ago

@robdodson

CSP environment

What's that?

rniwa commented 7 years ago

By default, CSP blocks the use of eval.

trusktr commented 7 years ago

I see, thanks. That'd be yet another complication to worry about. For my case, I've become content on supporting Edge 13 and up with native Classes, Proxies, and Reflect.construct to do some cool tricks.