diff --git a/CHANGELOG.md b/CHANGELOG.md index 42781ea1..3dd5243a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ - Added support for navigating the UI using a TV remote control. - Added a `tv-focus` attribute to specify which UI element should receive the initial focus when showing the controls on a TV. In the default UI, initial focus is on the seek bar. +- 🚀 Added a polyfill bundle in `@theoplayer/web-ui/polyfills`. This contains all the polyfills needed to use THEOplayer Web UI in legacy browsers, such as ES2015 `Promise` and Custom Elements. ([#41](https://github.com/THEOplayer/web-ui/pull/41)) ## v1.4.0 (2023-10-04) diff --git a/README.md b/README.md index 19f97750..07fe1567 100644 --- a/README.md +++ b/README.md @@ -129,7 +129,7 @@ See [docs/examples/custom-ui.html](https://github.com/THEOplayer/web-ui/blob/mai By default, THEOplayer Web UI targets modern browsers that support modern JavaScript syntax (such as [async/await](https://caniuse.com/async-functions)) and native [Custom Elements](https://caniuse.com/custom-elementsv1). This keeps the download size small, so your viewers can spend less time waiting for your page to load and start watching their video faster. -On older browsers (such as Internet Explorer 11 and older smart TVs), you need to load a different version of the THEOplayer Web UI that uses older JavaScript syntax. You also need to load additional polyfills for missing features such as Promises or Custom Elements. We recommend [Polyfill.io](https://polyfill.io/) and [Web Components Polyfills](https://github.com/webcomponents/polyfills) for these. +On older browsers (such as Internet Explorer 11 and older smart TVs), you need to load a different version of the THEOplayer Web UI that uses older JavaScript syntax. You also need to load additional polyfills for missing features such as Promises or Custom Elements. These are provided by our polyfill bundle in `@theoplayer/web-ui/polyfills`. Alternatively, you can use [Polyfill.io](https://polyfill.io/) and [Web Components Polyfills](https://github.com/webcomponents/polyfills). - Option 1: in your HTML. This uses [differential serving](https://css-tricks.com/differential-serving/) so modern browsers will load the modern build (with `type="module"`), while legacy browsers will load the legacy build (with `nomodule`). @@ -146,17 +146,14 @@ On older browsers (such as Internet Explorer 11 and older smart TVs), you need t - - - + ``` - Option 2: in your JavaScript. This will load the legacy build on both modern and legacy browsers, which is suboptimal. Instead, we recommend configuring your bundler to produce a modern and legacy build of your entire web app, and to import the appropriate version of THEOplayer Web UI for each build flavor. ```js - import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js'; - import '@webcomponents/webcomponentsjs/webcomponents-bundle.js'; + import '@theoplayer/web-ui/polyfills'; import { DefaultUI } from '@theoplayer/web-ui/es5'; // note the "/es5" suffix ``` diff --git a/docs/_layouts/example.html b/docs/_layouts/example.html index 5f86e6c6..e96598f0 100644 --- a/docs/_layouts/example.html +++ b/docs/_layouts/example.html @@ -24,10 +24,8 @@ - - - + {{ content }} diff --git a/package-lock.json b/package-lock.json index 599c3c5c..34991021 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,15 +8,19 @@ "name": "@theoplayer/web-ui", "version": "1.4.0", "license": "MIT", + "dependencies": { + "@webcomponents/webcomponentsjs": "^2.8.0", + "lit-html": "^3.0.0" + }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", + "@rollup/plugin-replace": "^5.0.4", "@rollup/pluginutils": "^5.0.4", "@swc/cli": "^0.1.62", "@swc/core": "^1.3.89", "@swc/helpers": "^0.5.2", "@types/html-minifier": "^4.0.3", "@webcomponents/shadycss": "^1.11.2", - "@webcomponents/webcomponentsjs": "^2.8.0", "html-minifier": "^4.0.0", "postcss": "^8.4.30", "postcss-mixins": "^9.0.4", @@ -890,6 +894,27 @@ } } }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.4.tgz", + "integrity": "sha512-E2hmRnlh09K8HGT0rOnnri9OTh+BILGr7NVJGB30S4E3cLRn3J0xjdiyOZ74adPs4NiAMgrjUMGAZNJDBgsdmQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@rollup/pluginutils": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", @@ -1291,6 +1316,11 @@ "@types/node": "*" } }, + "node_modules/@types/trusted-types": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", + "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==" + }, "node_modules/@types/uglify-js": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.2.tgz", @@ -1318,8 +1348,7 @@ "node_modules/@webcomponents/webcomponentsjs": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.8.0.tgz", - "integrity": "sha512-loGD63sacRzOzSJgQnB9ZAhaQGkN7wl2Zuw7tsphI5Isa0irijrRo6EnJii/GgjGefIFO8AIO7UivzRhFaEk9w==", - "dev": true + "integrity": "sha512-loGD63sacRzOzSJgQnB9ZAhaQGkN7wl2Zuw7tsphI5Isa0irijrRo6EnJii/GgjGefIFO8AIO7UivzRhFaEk9w==" }, "node_modules/ansi-sequence-parser": { "version": "1.1.1", @@ -2772,6 +2801,14 @@ "node": ">=10" } }, + "node_modules/lit-html": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.0.0.tgz", + "integrity": "sha512-DNJIE8dNY0dQF2Gs0sdMNUppMQT2/CvV4OVnSdg7BXAsGqkVwsE5bqQ04POfkYH5dBIuGnJYdFz5fYYyNnOxiA==", + "dependencies": { + "@types/trusted-types": "^2.0.2" + } + }, "node_modules/loader-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", @@ -5687,6 +5724,16 @@ "resolve": "^1.22.1" } }, + "@rollup/plugin-replace": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.4.tgz", + "integrity": "sha512-E2hmRnlh09K8HGT0rOnnri9OTh+BILGr7NVJGB30S4E3cLRn3J0xjdiyOZ74adPs4NiAMgrjUMGAZNJDBgsdmQ==", + "dev": true, + "requires": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + } + }, "@rollup/pluginutils": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.0.4.tgz", @@ -5939,6 +5986,11 @@ "@types/node": "*" } }, + "@types/trusted-types": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.4.tgz", + "integrity": "sha512-IDaobHimLQhjwsQ/NMwRVfa/yL7L/wriQPMhw1ZJall0KX6E1oxk29XMDeilW5qTIg5aoiqf5Udy8U/51aNoQQ==" + }, "@types/uglify-js": { "version": "3.17.2", "resolved": "https://registry.npmjs.org/@types/uglify-js/-/uglify-js-3.17.2.tgz", @@ -5965,8 +6017,7 @@ "@webcomponents/webcomponentsjs": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/@webcomponents/webcomponentsjs/-/webcomponentsjs-2.8.0.tgz", - "integrity": "sha512-loGD63sacRzOzSJgQnB9ZAhaQGkN7wl2Zuw7tsphI5Isa0irijrRo6EnJii/GgjGefIFO8AIO7UivzRhFaEk9w==", - "dev": true + "integrity": "sha512-loGD63sacRzOzSJgQnB9ZAhaQGkN7wl2Zuw7tsphI5Isa0irijrRo6EnJii/GgjGefIFO8AIO7UivzRhFaEk9w==" }, "ansi-sequence-parser": { "version": "1.1.1", @@ -6982,6 +7033,14 @@ "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", "dev": true }, + "lit-html": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-3.0.0.tgz", + "integrity": "sha512-DNJIE8dNY0dQF2Gs0sdMNUppMQT2/CvV4OVnSdg7BXAsGqkVwsE5bqQ04POfkYH5dBIuGnJYdFz5fYYyNnOxiA==", + "requires": { + "@types/trusted-types": "^2.0.2" + } + }, "loader-utils": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", diff --git a/package.json b/package.json index 20908d46..5870b25d 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "import": "./dist/THEOplayerUI.es5.mjs", "default": "./dist/THEOplayerUI.es5.js" }, + "./polyfills": "./dist/THEOplayerUI-polyfills.js", "./dist/*": "./dist/*" }, "files": [ @@ -46,18 +47,22 @@ "type": "git", "url": "git+https://github.com/THEOplayer/web-ui.git" }, + "dependencies": { + "@webcomponents/webcomponentsjs": "^2.8.0", + "lit-html": "^3.0.0" + }, "peerDependencies": { "theoplayer": "^6" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", + "@rollup/plugin-replace": "^5.0.4", "@rollup/pluginutils": "^5.0.4", "@swc/cli": "^0.1.62", "@swc/core": "^1.3.89", "@swc/helpers": "^0.5.2", "@types/html-minifier": "^4.0.3", "@webcomponents/shadycss": "^1.11.2", - "@webcomponents/webcomponentsjs": "^2.8.0", "html-minifier": "^4.0.0", "postcss": "^8.4.30", "postcss-mixins": "^9.0.4", diff --git a/rollup.config.mjs b/rollup.config.mjs index 3b68d5b4..ce96ddc6 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -8,6 +8,7 @@ import postcssMixins from 'postcss-mixins'; import * as path from 'node:path'; import { readFile } from 'node:fs/promises'; import { string } from 'rollup-plugin-string'; +import replace from '@rollup/plugin-replace'; import dts from 'rollup-plugin-dts'; const fileName = 'THEOplayerUI'; @@ -32,6 +33,18 @@ export default (cliArgs) => { return defineConfig([ ...jsConfig(outputDir, { es5: false, production, sourcemap: true }), ...jsConfig(outputDir, { es5: true, production, sourcemap: false }), + { + input: './src/polyfills.ts', + output: { + file: path.join(outputDir, `${fileName}.polyfills.js`), + format: 'iife', + sourcemap: false, + indent: false, + banner + }, + context: 'self', + plugins: jsPlugins({ es5: true, module: false, production: true, sourcemap: false }) + }, { input: './src/index.ts', output: { @@ -117,6 +130,16 @@ function jsPlugins({ es5 = false, module = false, production = false, sourcemap string({ include: ['./src/**/*.html', './src/**/*.svg'] }), + // Replace `globalThis` in lit-html. + es5 + ? replace({ + preventAssignment: true, + delimiters: ['\\b', '\\b'], + values: { + globalThis: 'self' + } + }) + : undefined, // Transpile TypeScript. swc({ include: './src/**', @@ -149,18 +172,16 @@ function jsPlugins({ es5 = false, module = false, production = false, sourcemap externalHelpers: true } }), - ...(production - ? [ - minify({ - sourceMap: sourcemap, - mangle: { - toplevel: true - }, - toplevel: true, - module, - ecma: es5 ? 5 : 2017 - }) - ] - : []) - ]; + production + ? minify({ + sourceMap: sourcemap, + mangle: { + toplevel: true + }, + toplevel: true, + module, + ecma: es5 ? 5 : 2017 + }) + : undefined + ].filter((plugin) => plugin !== undefined); } diff --git a/src/polyfills.ts b/src/polyfills.ts new file mode 100644 index 00000000..5f5b4c4c --- /dev/null +++ b/src/polyfills.ts @@ -0,0 +1,3 @@ +import '@webcomponents/webcomponentsjs/custom-elements-es5-adapter.js'; +import '@webcomponents/webcomponentsjs/webcomponents-bundle.js'; +import 'lit-html/polyfill-support.js';