Comments (5)
Hi @tconroy, the native shim can't be used compiled to ES5 because native custom elements implementations require that the HTMLElement
constructor is called as a constructor from your code and only features available in ES2015 are able to do this.
Particularly, when using the native custom element implementation, your definition either...
-
is written as a class extending
HTMLElement
and needs to callsuper
in the constructor:class MyElement extends HTMLElement { constructor() { super(); // `this` is now the element. this.prop = 1234; } } customElements.define('my-element', MyElement);
-
or, is written as a normal ES5 constructor and needs to call
Reflect.construct
, use its result instead ofthis
, and return that result:function MyElement() { // As usual, `this` does in fact exist here and it is an object // with `MyElement.prototype` as its prototype. However, there is // no way to call `HTMLElement` as a constructor while also // supplying the local `this` as the `this` value for the // construction. // To work around the above and because `super` has no meaning // within this function (or, more concretely, will cause a // SyntaxError), you must *construct* a new `HTMLElement`: var inst = Reflect.construct(HTMLElement, [], new.target); // Then, you can use the result as if it was `this`: inst.prop = 1234; // When plain functions are called as constructors and the function // returns undefined, the object that was automatically created to // become this (described in the first comment) is the result of // the construction. However, if the constructor returns an object // (primitives won't trigger this), that returned value is the // result of the construction: return inst; } MyElement.prototype = Object.create(HTMLElement.prototype); MyElement.prototype.constructor = MyElement; customElements.define('my-element', MyElement);
This ultimately means that if you give the native shim to a compiler to convert to ES5, the compiler will see the class and rewrite it in a way that it thinks is roughly equivalent - usually as a plain function with HTMLElement.call(this)
acting as super()
. However, because HTMLElement
can only be called as a constructor in one of the ways above, anything in pure ES5 that the compiler converts it to isn't sufficient.
The native shim is only meant to wrap a native implementation of custom elements so that custom element definitions that have specifically been compiled from ES2015 to ES5 will work there. Particularly, it will break if you try to run it in a client that doesn't have a native custom elements implementation because HTMLElement
won't be constructible. Also, because of how the native shim works right now, it doesn't work with ES2015 classes as custom element definitions - all definitions have to be compiled when using it. We'll look into it in the future but supporting mixed compilation situations doesn't seem to be that critical at the moment.
So, what do you actually need to do?
- If you decide to build (you're shipping ES5 definitions):
- If the client you're running on has a native implementation of custom elements, you need to load the native shim.
- Otherwise, you need to load the polyfill.
- If you decide not to build (you're shipping ES2015 definitions):
- If the client you're running on has a native implementation of custom elements, you don't need to do include anything else.
- Otherwise, you need to load the polyfill.
Also, you should load the polyfill separately, rather than bundling it with your app, so that clients that don't need it don't download it. If you're planning on using the full set of web components polyfills, take a look at the loader in webcomponentsjs; it checks what things are supported by the browser its running in and loads only the polyfills needed by that browser.
Here's a small example project that uses webpack and babel to compile custom elements written in ES2015 (with modules) to ES5 and load the native shim or polyfill as needed:
https://glitch.com/edit/#!/webpack-babel-custom-elements
(result: https://webpack-babel-custom-elements.glitch.me)
The document.write('<!--')
thing in index.html
looks pretty gnarly but it works reliably and we use it in polymer build
to optionally load the native shim. I've tried out that example project in IE11, mobile Safari 9, and most auto-updating browsers and everything checks out. However, the polyfill doesn't support Safari 8 (here are the browsers it does), so I can't say whether or not it will work there.
from custom-elements.
Sorry, I left out an important distinction: you can definitely call a function as a constructor in ES5 - new
:) - but the key part is that you can't pass new.target
like you can with Reflect.construct
and is implied with super()
. (The HTML spec's description of HTML element constructors has the details of why you need new.target
.) Also, that example might seem a bit strange since the polyfill / native shim are pretty separate from the webpack / babel stuff going on. (.. and serving directly from node_modules
, I was lazy.) The point is just that the native shim and polyfill should be loaded separately from your bundle if your server isn't deciding what clients get what bundles. One thing you might want to consider doing is minifying (but not compiling) the native shim, this is also something that webcomponentsjs does (description, minified native shim).
from custom-elements.
Hmm, looks like my example was a bit too janky and started creating this nested series of folders called 'built' - just updated it with a slightly more robust build process.
from custom-elements.
@Hotell would what you're doing in skatejs/web-components#48 help make this simpler for consumers?
from custom-elements.
ofc, with new skatejs/web-components everything is handled for you and you save 35kB in worst case scenario
best case - browser with full support of WC ( if you're transpiling to es5, just es5-adapter will be loaded - 2kb )
worst case - IE11 - lazy loaded polyfills/es6 needed features -> savings 35kb against webcomponnets shims in this repo
you can try it right now
- skate starter with typescript https://github.com/Hotell/skate-starter
from custom-elements.
Related Issues (20)
- Node.append() should be monkeypatched by custom-elements/src/Patch/Node.js HOT 2
- Use webcomponents-loader in webpack HOT 2
- Native ES6 classes do not work when the native-shim is in use. HOT 7
- Transpiling CEs to ES5 and loading them correctly HOT 1
- Object doesn't support property or method ... HOT 1
- Add support for `customElements.upgrade`.
- Constructor called twice in some cases HOT 2
- Duplicate declaration exception differs from original HOT 1
- CE polyfill is incompatible with babelHelpers class adapter HOT 4
- Modifying DOM in connectedCallback leads to wrong callback order for children. HOT 1
- No callbacks when using range.insertNode HOT 1
- Compiled version of custom-elements.min.js in latest version 1.1.2 does not exist in npm HOT 2
- Question: why use __ce_shadowRoot instead of shadowRoot HOT 7
- Error compiling m-datepicker HOT 1
- IE11/Edge errors SCRIPT28 and SCRIPT2343 (es5) HOT 2
- appreciate your feedback for custom element diagram HOT 7
- Can this polyfill be considered dead? HOT 2
- A browser extension overwrites HTMLElement.prototype.appendChild HOT 1
- Setting textContent to `null` or `undefined` incorrectly creates text with the string `null` or `undefined`
- Some errors thrown during define are squelched
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from custom-elements.