@webcomponents/webcomponentsjs
Advanced tools
Comparing version 1.2.0 to 2.0.0-0
@@ -10,3 +10,6 @@ { | ||
"sourceType": "module" | ||
} | ||
}, | ||
"plugins": [ | ||
"html" | ||
] | ||
} |
(function () { | ||
'use strict'; | ||
(()=>{'use strict';if(!window.customElements)return;const a=window.HTMLElement,b=window.customElements.define,c=window.customElements.get,d=new Map,e=new Map;let f=!1,g=!1;window.HTMLElement=function(){if(!f){const a=d.get(this.constructor),b=c.call(window.customElements,a);g=!0;const e=new b;return e}f=!1;},window.HTMLElement.prototype=a.prototype;Object.defineProperty(window,'customElements',{value:window.customElements,configurable:!0,writable:!0}),Object.defineProperty(window.customElements,'define',{value:(c,h)=>{const i=h.prototype,j=class extends a{constructor(){super(),Object.setPrototypeOf(this,i),g||(f=!0,h.call(this)),g=!1;}},k=j.prototype;j.observedAttributes=h.observedAttributes,k.connectedCallback=i.connectedCallback,k.disconnectedCallback=i.disconnectedCallback,k.attributeChangedCallback=i.attributeChangedCallback,k.adoptedCallback=i.adoptedCallback,d.set(h,c),e.set(c,h),b.call(window.customElements,c,j);},configurable:!0,writable:!0}),Object.defineProperty(window.customElements,'get',{value:(a)=>e.get(a),configurable:!0,writable:!0});})(); | ||
(()=>{if(!window.customElements)return;const a=window.HTMLElement,b=window.customElements.define,c=window.customElements.get,d=new Map,e=new Map;let f=!1,g=!1;window.HTMLElement=function(){if(!f){const a=d.get(this.constructor),b=c.call(window.customElements,a);g=!0;const e=new b;return e}f=!1;}, window.HTMLElement.prototype=a.prototype;Object.defineProperty(window,'customElements',{value:window.customElements,configurable:!0,writable:!0}), Object.defineProperty(window.customElements,'define',{value:(c,h)=>{const i=h.prototype,j=class extends a{constructor(){super(), Object.setPrototypeOf(this,i), g||(f=!0, h.call(this)), g=!1;}},k=j.prototype;j.observedAttributes=h.observedAttributes, k.connectedCallback=i.connectedCallback, k.disconnectedCallback=i.disconnectedCallback, k.attributeChangedCallback=i.attributeChangedCallback, k.adoptedCallback=i.adoptedCallback, d.set(h,c), e.set(c,h), b.call(window.customElements,c,j);},configurable:!0,writable:!0}), Object.defineProperty(window.customElements,'get',{value:a=>e.get(a),configurable:!0,writable:!0});})(); | ||
@@ -6,0 +6,0 @@ /** |
@@ -19,25 +19,2 @@ /** | ||
import '../node_modules/@webcomponents/custom-elements/src/custom-elements.js'; | ||
import '../node_modules/@webcomponents/shadycss/entrypoints/scoping-shim.js'; | ||
let document = window.document; | ||
// global for (1) existence means `WebComponentsReady` will file, | ||
// (2) WebComponents.ready == true means event has fired. | ||
window.WebComponents = window.WebComponents || {}; | ||
function fire() { | ||
requestAnimationFrame(() => { | ||
window.WebComponents.ready = true; | ||
window.document.dispatchEvent(new CustomEvent('WebComponentsReady', { bubbles: true })); | ||
}) | ||
} | ||
function wait() { | ||
fire(); | ||
document.removeEventListener('readystatechange', wait); | ||
} | ||
if (document.readyState !== 'loading') { | ||
fire(); | ||
} else { | ||
document.addEventListener('readystatechange', wait); | ||
} | ||
import '../node_modules/@webcomponents/shadycss/entrypoints/scoping-shim.js'; |
@@ -24,3 +24,6 @@ /** | ||
/** @type !Function */ | ||
Promise.cast; | ||
/** @type {!Function} */ | ||
Promise.cast; | ||
/** @type {function()} */ | ||
HTMLTemplateElement.bootstrap; |
121
gulpfile.js
@@ -19,4 +19,3 @@ /** | ||
const rename = require('gulp-rename'); | ||
const rollup = require('rollup-stream'); | ||
const source = require('vinyl-source-stream'); | ||
const rollup = require('gulp-rollup'); | ||
const del = require('del'); | ||
@@ -28,9 +27,16 @@ const runseq = require('run-sequence'); | ||
function debugify(sourceName, fileName, extraRollupOptions) { | ||
if (!fileName) | ||
const outDir = fileName ? '.' : './bundles'; | ||
if (!fileName) { | ||
fileName = sourceName; | ||
} | ||
const entry = `./entrypoints/${sourceName}-index.js`; | ||
const options = { | ||
entry: `./entrypoints/${sourceName}-index.js`, | ||
format: 'iife', | ||
moduleName: 'webcomponentsjs' | ||
input: entry, | ||
output: { | ||
format: 'iife', | ||
name: 'webcomponentsjs' | ||
}, | ||
allowRealFiles: true | ||
}; | ||
@@ -40,9 +46,11 @@ | ||
return rollup(options) | ||
.pipe(source(`${sourceName}-index.js`), 'entrypoints') | ||
.pipe(rename(fileName + '.js')) | ||
.pipe(gulp.dest('./')) | ||
return gulp.src(entry) | ||
.pipe(rollup(options)) | ||
.pipe(rename(`${fileName}.js`)) | ||
.pipe(gulp.dest(outDir)) | ||
} | ||
function closurify(sourceName, fileName) { | ||
const outDir = fileName ? '.' : './bundles'; | ||
if (!fileName) { | ||
@@ -53,3 +61,2 @@ fileName = sourceName; | ||
const closureOptions = { | ||
new_type_inf: true, | ||
compilation_level: 'ADVANCED', | ||
@@ -70,3 +77,2 @@ language_in: 'ES6_STRICT', | ||
'node_modules/@webcomponents/custom-elements/externs/custom-elements.js', | ||
'node_modules/@webcomponents/html-imports/externs/html-imports.js', | ||
'node_modules/@webcomponents/shadycss/externs/shadycss-externs.js', | ||
@@ -89,22 +95,16 @@ 'node_modules/@webcomponents/shadydom/externs/shadydom.js' | ||
.pipe(sourcemaps.write('.')) | ||
.pipe(gulp.dest('.')); | ||
.pipe(gulp.dest(outDir)); | ||
} | ||
gulp.task('debugify-hi', () => { | ||
return debugify('webcomponents-hi') | ||
gulp.task('debugify-ce', () => { | ||
return debugify('webcomponents-ce') | ||
}); | ||
gulp.task('debugify-hi-ce', () => { | ||
return debugify('webcomponents-hi-ce') | ||
}); | ||
gulp.task('debugify-hi-sd-ce', () => { | ||
return debugify('webcomponents-hi-sd-ce') | ||
}); | ||
gulp.task('debugify-hi-sd-ce-pf', () => { | ||
gulp.task('debugify-sd-ce-pf', () => { | ||
// The es6-promise polyfill needs to set the correct context. | ||
// See https://github.com/rollup/rollup/wiki/Troubleshooting#this-is-undefined | ||
const extraOptions = {context: 'window'}; | ||
return debugify('webcomponents-hi-sd-ce-pf', 'webcomponents-lite', extraOptions) | ||
const extraOptions = { | ||
context: 'window' | ||
}; | ||
return debugify('webcomponents-sd-ce-pf', null, extraOptions) | ||
}); | ||
@@ -116,30 +116,35 @@ | ||
gulp.task('debugify-hi-sd', () => { | ||
return debugify('webcomponents-hi-sd') | ||
gulp.task('debugify-sd', () => { | ||
return debugify('webcomponents-sd') | ||
}); | ||
gulp.task('closurify-hi', () => { | ||
return closurify('webcomponents-hi') | ||
gulp.task('debugify-bundle', () => { | ||
// The es6-promise polyfill needs to set the correct context. | ||
// See https://github.com/rollup/rollup/wiki/Troubleshooting#this-is-undefined | ||
const extraOptions = { | ||
context: 'window' | ||
}; | ||
return debugify('webcomponents-bundle', 'webcomponents-bundle', extraOptions); | ||
}) | ||
gulp.task('closurify-ce', () => { | ||
return closurify('webcomponents-ce') | ||
}); | ||
gulp.task('closurify-hi-ce', () => { | ||
return closurify('webcomponents-hi-ce') | ||
gulp.task('closurify-sd-ce-pf', () => { | ||
return closurify('webcomponents-sd-ce-pf') | ||
}); | ||
gulp.task('closurify-hi-sd-ce', () => { | ||
return closurify('webcomponents-hi-sd-ce') | ||
gulp.task('closurify-sd-ce', () => { | ||
return closurify('webcomponents-sd-ce') | ||
}); | ||
gulp.task('closurify-hi-sd-ce-pf', () => { | ||
return closurify('webcomponents-hi-sd-ce-pf', 'webcomponents-lite') | ||
gulp.task('closurify-sd', () => { | ||
return closurify('webcomponents-sd') | ||
}); | ||
gulp.task('closurify-sd-ce', () => { | ||
return closurify('webcomponents-sd-ce') | ||
gulp.task('closurify-bundle', () => { | ||
return closurify('webcomponents-bundle', 'webcomponents-bundle'); | ||
}); | ||
gulp.task('closurify-hi-sd', () => { | ||
return closurify('webcomponents-hi-sd') | ||
}) | ||
function singleLicenseComment() { | ||
@@ -161,3 +166,3 @@ let hasLicense = false; | ||
gulp.task('debugify-ce-es5-adapter', () => { | ||
return debugify('custom-elements-es5-adapter', '', {plugins: [babel(babelOptions)]}); | ||
return debugify('custom-elements-es5-adapter', 'custom-elements-es5-adapter', {plugins: [babel(babelOptions)]}); | ||
}); | ||
@@ -167,4 +172,8 @@ | ||
gulp.task('clean-builds', () => { | ||
return del(['custom-elements-es5-adapter.js{,.map}', 'webcomponents*.js{,.map}', '!webcomponents-loader.js']); | ||
gulp.task('clean', () => { | ||
return del([ | ||
'custom-elements-es5-adapter.js{,.map}', | ||
'bundles', | ||
'webcomponents-bundle.js{,.map}' | ||
]); | ||
}); | ||
@@ -174,11 +183,10 @@ | ||
const tasks = [ | ||
'debugify-hi', | ||
'debugify-hi-ce', | ||
'debugify-hi-sd', | ||
'debugify-hi-sd-ce', | ||
'debugify-hi-sd-ce-pf', | ||
'debugify-ce', | ||
'debugify-sd', | ||
'debugify-sd-ce', | ||
'debugify-sd-ce-pf', | ||
'debugify-bundle', | ||
'debugify-ce-es5-adapter' | ||
]; | ||
runseq('clean-builds', tasks, cb); | ||
runseq('clean', tasks, cb); | ||
}); | ||
@@ -188,11 +196,10 @@ | ||
const tasks = [ | ||
'closurify-hi', | ||
'closurify-hi-ce', | ||
'closurify-hi-sd', | ||
'closurify-hi-sd-ce', | ||
'closurify-hi-sd-ce-pf', | ||
'closurify-ce', | ||
'closurify-sd', | ||
'closurify-sd-ce', | ||
'closurify-sd-ce-pf', | ||
'closurify-bundle', | ||
'debugify-ce-es5-adapter' | ||
]; | ||
runseq('clean-builds', ...tasks, cb); | ||
runseq('clean', ...tasks, cb); | ||
}); |
{ | ||
"name": "@webcomponents/webcomponentsjs", | ||
"version": "1.2.0", | ||
"version": "2.0.0-0", | ||
"description": "Web Components Polyfills", | ||
@@ -26,28 +26,31 @@ "main": "webcomponents-lite.js", | ||
"build": "gulp", | ||
"test": "wct" | ||
"test": "wct --npm" | ||
}, | ||
"homepage": "https://webcomponents.org/polyfills", | ||
"devDependencies": { | ||
"@babel/plugin-transform-classes": "7.0.0-beta.35", | ||
"@webcomponents/custom-elements": "^1.1.0", | ||
"@webcomponents/html-imports": "^1.1.1", | ||
"@webcomponents/shadycss": "^1.1.3", | ||
"@webcomponents/shadycss": "^1.2.0-0", | ||
"@webcomponents/shadydom": "^1.0.14", | ||
"@webcomponents/template": "^1.2.4", | ||
"@webcomponents/url": "^0.7.0", | ||
"@webcomponents/webcomponents-platform": "^1.0.0", | ||
"babel-preset-minify": "^0.2.0", | ||
"babel-preset-minify": "^0.4.0", | ||
"del": "^3.0.0", | ||
"es6-promise": "4.1.x", | ||
"eslint": "^4.19.1", | ||
"eslint-plugin-html": "^4.0.2", | ||
"google-closure-compiler": "^20171203.0.0", | ||
"gulp": "^3.8.8", | ||
"gulp-add-src": "^0.2.0", | ||
"gulp-header": "^1.8.12", | ||
"gulp-rename": "^1.2.2", | ||
"gulp-rollup": "^2.16.2", | ||
"gulp-sourcemaps": "^2.6.4", | ||
"rollup-plugin-babel": "^2.7.1", | ||
"rollup-stream": "=1.23", | ||
"rollup-plugin-node-resolve": "^3.3.0", | ||
"run-sequence": "^2.2.1", | ||
"vinyl-buffer": "^1.0.1", | ||
"vinyl-source-stream": "^1.1.2", | ||
"web-component-tester": "^6.5.0" | ||
"wct-browser-legacy": "0.0.1-pre.12", | ||
"web-component-tester": "^6.6.0-pre.5" | ||
}, | ||
@@ -54,0 +57,0 @@ "publishConfig": { |
191
README.md
webcomponents.js (v1 spec polyfills) | ||
================ | ||
[![Build Status](https://travis-ci.org/webcomponents/webcomponentsjs.svg?branch=master)](https://travis-ci.org/webcomponents/webcomponentsjs) | ||
[![Build Status](https://travis-ci.org/webcomponents/webcomponentsjs.svg?branch=master)] | ||
(https://travis-ci.org/webcomponents/webcomponentsjs) | ||
> **Note**. For polyfills that work with the older Custom Elements and Shadow DOM v0 specs, see the [v0 branch](https://github.com/webcomponents/webcomponentsjs/tree/v0). | ||
> **Note**. For polyfills that work with the older Custom Elements and Shadow DOM v0 specs, | ||
see the [v0 branch](https://github.com/webcomponents/webcomponentsjs/tree/v0). | ||
> **Note**. For polyfills that include HTML Imports, | ||
see the [v1 branch](https://github.com/webcomponents/webcomponentsjs/tree/v1). | ||
A suite of polyfills supporting the [Web Components](http://webcomponents.org) specs: | ||
- **Custom Elements v1**: allows authors to define their own custom tags ([spec](https://w3c.github.io/webcomponents/spec/custom/), [tutorial](https://developers.google.com/web/fundamentals/getting-started/primers/customelements)). | ||
- **HTML Imports**: a way to include and reuse HTML documents via other HTML documents ([spec](https://w3c.github.io/webcomponents/spec/imports/), [tutorial](https://www.html5rocks.com/en/tutorials/webcomponents/imports/)). | ||
- **Shadow DOM v1**: provides encapsulation by hiding DOM subtrees under shadow roots ([spec](https://w3c.github.io/webcomponents/spec/shadow/), [tutorial](https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom)). | ||
- **Custom Elements v1**: allows authors to define their own custom tags ([spec](https://w3c.github.io/webcomponents/spec/custom/), [tutorial](https://developers.google.com/web/fundamentals/getting-started/primers/customelements), [polyfill](https://github.com/webcomponents/custom-elements)). | ||
- **Shadow DOM v1**: provides encapsulation by hiding DOM subtrees under shadow roots ([spec](https://w3c.github.io/webcomponents/spec/shadow/), [tutorial](https://developers.google.com/web/fundamentals/getting-started/primers/shadowdom), | ||
[shadydom polyfill](https://github.com/webcomponents/shadydom), [shadycss polyfill](https://github.com/webcomponents/shadycss)). | ||
@@ -17,71 +22,125 @@ For browsers that need it, there are also some minor polyfills included: | ||
- [`Promise`](https://github.com/stefanpenner/es6-promise) | ||
- `Event`, `CustomEvent`, `MouseEvent` constructors and `Object.assign`, `Array.from` (see [webcomponents-platform](https://github.com/webcomponents/webcomponents-platform)) | ||
- `Event`, `CustomEvent`, `MouseEvent` constructors and `Object.assign`, `Array.from` | ||
(see [webcomponents-platform](https://github.com/webcomponents/webcomponents-platform)) | ||
- [`URL constructor`](https://github.com/webcomponents/URL) | ||
## How to use | ||
The polyfills are built (concatenated & minified) into several bundles that target | ||
different browsers and spec readiness: | ||
### Using `webcomponents-bundle.js` | ||
- `webcomponents-hi.js` -- HTML Imports (needed by Safari Tech Preview) | ||
- `webcomponents-hi-ce.js` -- HTML Imports and Custom Elements v1 (needed by Safari 10) | ||
- `webcomponents-hi-sd-ce.js` -- HTML Imports, Custom Elements v1 and Shady DOM/CSS (needed by Safari 9, Firefox, Edge) | ||
- `webcomponents-sd-ce.js` -- Custom Elements and Shady DOM/CSS (no HTML Imports) | ||
- `webcomponents-lite.js` -- all of the polyfills: HTML Imports, Custom Elements, Shady DOM/CSS and generic platform polyfills (such as ES6 Promise, Constructable events, etc.) (needed by Internet Explorer 11), and Template (needed by IE 11 and Edge) | ||
The `webcomponents-bundle.js` contains all of the web components polyfills and is | ||
suitable for use on any supported browser. All of the polyfill code will be loaded | ||
but each polyfill will only be used based on feature detection. | ||
The bundle includes Custom Elements, Shady DOM/CSS and generic platform polyfills | ||
(such as ES6 Promise, Constructable events, etc.) (needed by Internet Explorer 11), | ||
and Template (needed by IE 11 and Edge). | ||
If you are only targeting a specific browser, you can just use the bundle that's | ||
needed by it; alternatively, if your server is capable of serving different assets based on user agent, you can send the polyfill bundle that's necessary for the browser making that request. | ||
The `webcomponents-bundle.js` is very simple to use but it does load code | ||
that is not needed on most modern browsers, slowing page load. For best performance, | ||
use the `webcomponents-loader.js`. | ||
## `webcomponents-loader.js` | ||
Alternatively, this repo also comes with `webcomponents-loader.js`, a client-side | ||
loader that dynamically loads the minimum polyfill bundle, using feature detection. | ||
Note that because the bundle will be loaded asynchronously, you should wait for the `WebComponentsReady` before you can safely assume that all the polyfills have | ||
loaded and are ready to be used (i.e. if you want to dynamically load other custom | ||
elements, etc.). | ||
Here's an example: | ||
Additionally, you can check if `window.WebComponents` exists to know if the `WebComponentsReady` event will fire, and you can check if `window.WebComponents.ready` is true to check if the `WebComponentsReady` event has already fired. | ||
```html | ||
<!-- load webcomponents bundle, which includes all the necessary polyfills --> | ||
<script src="node_modules/webcomponentsjs/webcomponents-bundle.js"></script> | ||
<!-- load the element --> | ||
<script type="module" src="my-element.js"></script> | ||
<!-- use the element --> | ||
<my-element></my-element> | ||
``` | ||
### Using `webcomponents-loader.js` | ||
The `webcomponents-loader.js` is a client-side loader that dynamically loads the | ||
minimum polyfill bundle, using feature detection. | ||
`webcomponents-loader.js` can be loaded synchronously, or asynchronously depending on your needs. | ||
#### Synchronous | ||
When loaded synchronously, `webcomponents-loader.js` behaves similarly to `webcomponents-bundle.js`. | ||
The appropriate bundle will be loaded with `document.write()` to ensure that WebComponent polyfills are available for subsequent scripts and modules. | ||
Here's an example: | ||
```html | ||
<!-- Load polyfills; note that "loader" will load these async --> | ||
<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script> | ||
<!-- load the webcomponents loader, which injects the necessary polyfill bundle --> | ||
<script src="node_modules/webcomponentsjs/webcomponents-loader.js"></script> | ||
<!-- Load a custom element definition via HTMLImports --> | ||
<link rel="import" href="my-element.html"> | ||
<!-- load the element --> | ||
<script type="module" src="my-element.js"></script> | ||
<!-- Use the custom element --> | ||
<!-- use the element --> | ||
<my-element></my-element> | ||
``` | ||
<!-- Interact with the upgraded element --> | ||
<script> | ||
window.addEventListener('WebComponentsReady', function() { | ||
// At this point we are guaranteed that all required polyfills have loaded, | ||
// all HTML imports have loaded, and all defined custom elements have upgraded | ||
let MyElement = customElements.get('my-element'); | ||
let element = document.querySelector('my-element'); | ||
console.assert(element instanceof MyElement); // 👍 | ||
element.someAPI(); // 👍 | ||
#### Asynchronous | ||
When loaded asychronously with the `defer` attribute, polyfill bundles will be loaded asynchronously, | ||
which means that scripts and modules that depend on webcomponents APIs *must* be loaded | ||
using `WebComponents.waitFor` function. | ||
The `WebComponents.waitFor` function takes a callback function as an argument, and will evaluate that callback after the polyfill bundle has been loaded. | ||
The callback function should load scripts that need the polyfills (typically via `import('my-script.js')`) and | ||
should return a promise that resolves when all scripts have loaded. | ||
Here's an example: | ||
```html | ||
<!-- Load polyfills; note that "loader" will load these async --> | ||
<script src="node_modules/webcomponentsjs/webcomponents-loader.js" defer></script> | ||
<!-- Load a custom element definitions in `waitFor` and return a promise --> | ||
<script type="module"> | ||
WebComponents.waitFor(() => { | ||
// At this point we are guaranteed that all required polyfills have | ||
// loaded, and can use web components API's. | ||
// The standard pattern is to load element definitions that call | ||
// `customElements.define` here. | ||
// Note: returning the import's promise causes the custom elements | ||
// polyfill to wait until all definitions are loaded and then upgrade | ||
// the document in one batch, for better performance. | ||
return import('my-element.js'); | ||
}); | ||
</script> | ||
<!-- Use the custom element --> | ||
<my-element></my-element> | ||
``` | ||
## `custom-elements-es5-adapter.js` | ||
According to the spec, Custom Elements must be ES6 classes (https://html.spec.whatwg.org/multipage/scripting.html#custom-element-conformance). Since most projects need to support a wide range of browsers that don't necessary support ES6, it may make sense to compile your project to ES5. However, ES5-style custom element classes will **not** work with native Custom Elements because ES5-style classes cannot properly extend ES6 classes, like `HTMLElement`. | ||
The `WebComponents.waitFor` function may be called multiple times, and the callback functions will be processed in order. | ||
To work around this, load `custom-elements-es5-adapter.js` before declaring new Custom Elements. | ||
Here's a more complicated example: | ||
**The adapter must NOT be compiled.** | ||
```html | ||
<!-- Load Custom Elements es5 adapter --> | ||
<script src="bower_components/webcomponentsjs/custom-elements-es5-adapter.js"></script> | ||
<!-- Load polyfills; note that "loader" will load these async --> | ||
<script src="bower_components/webcomponentsjs/webcomponents-loader.js"></script> | ||
<!-- Load the es5 compiled custom element definition --> | ||
<link rel="import" href="my-es5-element.html"> | ||
<script src="node_modules/webcomponentsjs/webcomponents-loader.js" defer></script> | ||
<!-- Use the custom element --> | ||
<my-es5-element></my-es5-element> | ||
<script type="module"> | ||
WebComponents.waitFor(async () => { | ||
if (!window.fetch) { | ||
await import('node_modules/fetch-polyfill/fetch.js'); | ||
} | ||
return import('my-element.js'); | ||
}) | ||
</script> | ||
<script type="module"> | ||
</script> | ||
``` | ||
### WebComponentsReady event | ||
The `WebComponentsReady` event is fired when polyfills and user scripts have loaded and custom elements have been upgraded. This event is generally not needed; however, it may be useful in some cases like testing. If imperative code should wait until a specific custom element definition has loaded, it can use the platform `customElements.whenDefined` API. | ||
### `custom-elements-es5-adapter.js` | ||
According to the spec, only ES6 classes (https://html.spec.whatwg.org/multipage/scripting.html#custom-element-conformance) may be passed to the _native_ `customElements.define` API. For best performnace, ES6 should be served to browsers that support it, and ES5 code should be serve to those that don't. Since this may not always be possible, it may make sense to compile and serve ES5 to all browsers. However, ES5-style custom element classes will **not** work on browsers with native Custom Elements because ES5-style classes cannot properly extend ES6 classes, like `HTMLElement`. | ||
To work around this, load `custom-elements-es5-adapter.js` before defining Custom Elements. This adapter will automatically wrap ES5. | ||
**The adapter must NOT be compiled.** | ||
## Browser Support | ||
@@ -92,7 +151,6 @@ | ||
| Polyfill | IE11+ | Chrome* | Firefox* | Safari 9+* | Chrome Android* | Mobile Safari* | | ||
| ---------- |:-----:|:-------:|:--------:|:----------:|:---------------:|:--------------:| | ||
| Custom Elements | ✓ | ✓ | ✓ | ✓ | ✓| ✓ | | ||
| HTML Imports | ✓ | ✓ | ✓ | ✓| ✓| ✓ | | ||
| Shady CSS/DOM | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ||
| Polyfill | Edge | IE11+ | Chrome* | Firefox* | Safari 9+* | Chrome Android* | Mobile Safari* | | ||
| ---------- |:----:|:-----:|:-------:|:--------:|:----------:|:---------------:|:--------------:| | ||
| Custom Elements | ✓ | ✓ | ✓ | ✓ | ✓ | ✓| ✓ | | ||
| Shady CSS/DOM | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | | ||
@@ -116,5 +174,4 @@ \*Indicates the current version of the browser | ||
npm install | ||
bower install | ||
# build | ||
gulp | ||
npm run build | ||
@@ -133,19 +190,9 @@ The builds will be placed into the root directory. | ||
## Helper utilities | ||
## Changes in version 2.x | ||
### `WebComponentsReady` | ||
* The HTML Imports polyfill has been removed. Given that ES modules have shipped in | ||
most browsers, the expectation is that web components code will be loaded via | ||
ES modules. | ||
* When using `webcomponents-loader.js` with the `defer` attribute, scripts that rely on the polyfills *must* be loaded using `WebComponents.waitFor(loadCallback)`. | ||
Under native HTML Imports, `<script>` tags in the main document block the loading of such imports. This is to ensure the imports have loaded and any registered elements in them have been upgraded. | ||
The `webcomponents-lite.js` polyfill (as well as the smaller bundles and the loader) parse element definitions and handle their upgrade asynchronously. If prematurely fetching the element from the DOM before it has an opportunity to upgrade, you'll be working with an `HTMLUnknownElement`. | ||
For these situations, you can use the `WebComponentsReady` event as a signal before interacting with the element. The criteria for this event to fire is all Custom Elements with definitions registered by the time HTML Imports available at load time have loaded have upgraded. | ||
```js | ||
window.addEventListener('WebComponentsReady', function(e) { | ||
// imports are loaded and elements have been registered | ||
console.log('Components are ready'); | ||
}); | ||
``` | ||
## Known Issues | ||
@@ -157,3 +204,3 @@ | ||
* [ShadyCSS: :host(.zot:not(.bar:nth-child(2))) doesn't work](#nestedparens) | ||
### ShadowDOM CSS is not encapsulated out of the box <a id="shadycss"></a> | ||
@@ -165,3 +212,3 @@ The ShadowDOM polyfill is not able to encapsulate CSS in ShadowDOM out of the box. You need to use specific code from the ShadyCSS library, included with the polyfill. See [ShadyCSS instructions](https://github.com/webcomponents/shadycss). | ||
In Safari and IE, instances of Custom Elements have a `constructor` property of `HTMLUnknownElementConstructor` and `HTMLUnknownElement`, respectively. It's unsafe to rely on this property for checking element types. | ||
In Edge and IE, instances of Custom Elements have a `constructor` property of `HTMLUnknownElementConstructor` and `HTMLUnknownElement`, respectively. It's unsafe to rely on this property for checking element types. | ||
@@ -168,0 +215,0 @@ It's worth noting that `customElement.__proto__.__proto__.constructor` is `HTMLElementPrototype` and that the prototype chain isn't modified by the polyfills(onto `ElementPrototype`, etc.) |
@@ -5,3 +5,17 @@ { | ||
"environmentImports": [] | ||
}, | ||
"plugins": { | ||
"local": { | ||
"browserOptions": { | ||
"chrome": [ | ||
"headless", | ||
"disable-gpu", | ||
"no-sandbox" | ||
], | ||
"firefox": [ | ||
"-headless" | ||
] | ||
} | ||
} | ||
} | ||
} |
/** | ||
* @license | ||
* Copyright (c) 2017 The Polymer Project Authors. All rights reserved. | ||
* Copyright (c) 2018 The Polymer Project Authors. All rights reserved. | ||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt | ||
@@ -13,11 +13,99 @@ * The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt | ||
'use strict'; | ||
// global for (1) existence means `WebComponentsReady` will fire, | ||
// (2) WebComponents.ready == true means event has fired. | ||
window.WebComponents = window.WebComponents || {}; | ||
/** | ||
* Basic flow of the loader process | ||
* | ||
* There are 4 flows the loader can take when booting up | ||
* | ||
* - Synchronous script, no polyfills needed | ||
* - wait for `DOMContentLoaded` | ||
* - run callbacks passed to `waitFor` | ||
* - fire WCR event | ||
* | ||
* - Synchronous script, polyfills needed | ||
* - document.write the polyfill bundle | ||
* - wait on the `load` event of the bundle to batch Custom Element upgrades | ||
* - wait for `DOMContentLoaded` | ||
* - run callbacks passed to `waitFor` | ||
* - fire WCR event | ||
* | ||
* - Asynchronous script, no polyfills needed | ||
* - fire WCR event, as there could not be any callbacks passed to `waitFor` | ||
* | ||
* - Asynchronous script, polyfills needed | ||
* - Append the polyfill bundle script | ||
* - wait for `load` event of the bundle | ||
* - batch Custom Element Upgrades | ||
* - run callbacks pass to `waitFor` | ||
* - fire WCR event | ||
*/ | ||
var polyfillsLoaded = false; | ||
var whenLoadedFns = []; | ||
var allowUpgrades = false; | ||
var flushFn; | ||
function fireEvent() { | ||
window.WebComponents.ready = true; | ||
document.dispatchEvent(new CustomEvent('WebComponentsReady', { bubbles: true })); | ||
} | ||
function batchCustomElements() { | ||
if (window.customElements && customElements.polyfillWrapFlushCallback) { | ||
customElements.polyfillWrapFlushCallback(function (flushCallback) { | ||
flushFn = flushCallback; | ||
if (allowUpgrades) { | ||
flushFn(); | ||
} | ||
}); | ||
} | ||
} | ||
function asyncReady() { | ||
batchCustomElements(); | ||
ready(); | ||
} | ||
function ready() { | ||
// bootstrap <template> elements before custom elements | ||
if (window.HTMLTemplateElement && HTMLTemplateElement.bootstrap) { | ||
HTMLTemplateElement.bootstrap(window.document); | ||
} | ||
polyfillsLoaded = true; | ||
runWhenLoadedFns().then(fireEvent); | ||
} | ||
function runWhenLoadedFns() { | ||
allowUpgrades = false; | ||
var done = function() { | ||
allowUpgrades = true; | ||
whenLoadedFns.length = 0; | ||
flushFn && flushFn(); | ||
}; | ||
return Promise.all(whenLoadedFns.map(function(fn) { | ||
return fn instanceof Function ? fn() : fn; | ||
})).then(function() { | ||
done(); | ||
}).catch(function(err) { | ||
console.error(err); | ||
}); | ||
} | ||
window.WebComponents = window.WebComponents || { | ||
ready: false, | ||
_batchCustomElements: batchCustomElements, | ||
waitFor: function(waitFn) { | ||
if (!waitFn) { | ||
return; | ||
} | ||
whenLoadedFns.push(waitFn); | ||
if (polyfillsLoaded) { | ||
runWhenLoadedFns(); | ||
} | ||
} | ||
}; | ||
var name = 'webcomponents-loader.js'; | ||
// Feature detect which polyfill needs to be imported. | ||
var polyfills = []; | ||
if (!('import' in document.createElement('link'))) { | ||
polyfills.push('hi'); | ||
} | ||
if (!('attachShadow' in Element.prototype && 'getRootNode' in Element.prototype) || | ||
@@ -31,7 +119,7 @@ (window.ShadyDOM && window.ShadyDOM.force)) { | ||
// NOTE: any browser that does not have template or ES6 features | ||
// must load the full suite (called `lite` for legacy reasons) of polyfills. | ||
if (!('content' in document.createElement('template')) || !window.Promise || !Array.from || | ||
// must load the full suite of polyfills. | ||
if (!('content' in document.createElement('template')) || !window.Promise || !Array.from || !window.URL || | ||
// Edge has broken fragment cloning which means you cannot clone template.content | ||
!(document.createDocumentFragment().cloneNode() instanceof DocumentFragment)) { | ||
polyfills = ['lite']; | ||
polyfills = ['sd-ce-pf']; | ||
} | ||
@@ -43,35 +131,28 @@ | ||
// Load it from the right place. | ||
var replacement = 'webcomponents-' + polyfills.join('-') + '.js'; | ||
var replacement = 'bundles/webcomponents-' + polyfills.join('-') + '.js'; | ||
var url = script.src.replace(name, replacement); | ||
newScript.src = url; | ||
// NOTE: this is required to ensure the polyfills are loaded before | ||
// *native* html imports load on older Chrome versions. This *is* CSP | ||
// compliant since CSP rules must have allowed this script to run. | ||
// In all other cases, this can be async. | ||
if (document.readyState === 'loading' && ('import' in document.createElement('link'))) { | ||
// if readyState is 'loading', this script is synchronous | ||
if (document.readyState === 'loading') { | ||
// make sure custom elements are batched whenever parser gets to the injected script | ||
newScript.setAttribute('onload', 'window.WebComponents._batchCustomElements()'); | ||
document.write(newScript.outerHTML); | ||
document.addEventListener('DOMContentLoaded', ready); | ||
} else { | ||
newScript.addEventListener('load', function () { | ||
asyncReady(); | ||
}); | ||
newScript.addEventListener('error', function () { | ||
throw new Error('Could not load polyfill bundle' + url); | ||
}); | ||
document.head.appendChild(newScript); | ||
} | ||
} else { | ||
// Ensure `WebComponentsReady` is fired also when there are no polyfills loaded. | ||
// however, we have to wait for the document to be in 'interactive' state, | ||
// otherwise a rAF may fire before scripts in <body> | ||
var fire = function() { | ||
requestAnimationFrame(function() { | ||
window.WebComponents.ready = true; | ||
document.dispatchEvent(new CustomEvent('WebComponentsReady', {bubbles: true})); | ||
}); | ||
}; | ||
if (document.readyState !== 'loading') { | ||
fire(); | ||
polyfillsLoaded = true; | ||
if (document.readyState === 'complete') { | ||
fireEvent() | ||
} else { | ||
document.addEventListener('readystatechange', function wait() { | ||
fire(); | ||
document.removeEventListener('readystatechange', wait); | ||
}); | ||
window.addEventListener('DOMContentLoaded', ready) | ||
} | ||
} | ||
})(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
77
2453
217
2372988
25
3
1