100% standard-compliant polyfill to allow WebComponent re-definition at runtime (used for HMR)
At the time of the creation of this readme, the API customElements.define(...)
doesn't allow to
re-define a Web Component with the same tag name but a different implementation. This limitation
made it impossible to do Hot Module Replacement (HMR) with standard Web Components. -
until today.
npm install custom-elements-hmr-polyfill
This polyfill overrides the native browser API customElement.define
and enables re-definition of
Web Components at runtime.
import { applyPolyfill } from 'custom-elements-hmr-polyfill';
// custom-elements-hmr-polyfill
applyPolyfill();
// reset the root to trigger rerender after the HMR event
if (document.body) {
requestAnimationFrame(() => {
document.body.innerHTML = '';
document.body.innerHTML = '<root-app></root-app>';
});
}
export class RootApp extends HTMLElement {
private name = 'I am RootApp';
connectedCallback() {
this.innerHTML = `
<div style="background-color:green">${this.name}</div>
`;
}
}
// PS! customElements.define can be called more then once when running pollyfil
// it need to do this to activate new instance
customElements.define('root-app', RootApp);
This polyfill requires support of the following browser API's (natively).
Proxy
MutationObserver
customElements
1:
attributeChangedCallback
returned namespace will be null Not sure how namespaces works for
attributes atm...
2:
Since HMR polyfill wraps your class in a proxy, you need to use customElements.get('my-element')
to get the class thats sent to customElements.define()
.
Sample under will not work, since your class isn't really sent to customELements.define
, a proxy
handler is.
class MyElement extends HTMLElement {}
window.customElements.define('my-element', MyElement);
new MyElement();
Solution:
class MyElement extends HTMLElement {}
window.customElements.define('my-element', MyElement);
const MyElementHMR = customElements.get('my-element');
new MyElementHMR();
Or just use document.createElement('my-element')
3:
Some elements dont like the deep patching we do, like lit-element.
Solution: You can try with (window as any).HMR_SKIP_DEEP_PATCH = true
to skip some of this.
4:
Atm I return empty array on observedAttributes in the proxy so browser dont get them. This might
create issues for some libs, if it does we can maybe add a option to return a array and just
overlook some elements might be called 2 times
5:
Some elements just do a lot and have own state containers / instance variables I cant do much about.
Try and load these before this polyfill, you really dont need these to be redefined..
--
For reference see: W3C/WhatWG standard limitation of Web Component re-definition.
The bundled npm package contains the following formats:
- IIFE (
.iife.js
) - AMD (
.amd.js
) - Common JS (
.cjs.js
) - ES Module (
.mjs
) - SystemJS (
.system.js
) - UMD (
.umd.js
)
You can find single file outputs in dist/custom-elements-hmr-polyfill.*
, i.e.
dist/custom-elements-hmr-polyfill.iife.js
.
Furthermore, multiple file outputs are available in dist/*/**/*.js
. i.e. dist/AMD/**/*.js
.
AMD
CommonJS
ES6
ES2015
ESNext
System
UMD
npm run bootstrap
npm start
npm run bootstrap
npm build