Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Redefine browser requirements for modern (latest) builds #16506

Merged
merged 10 commits into from
Jul 19, 2024
35 changes: 16 additions & 19 deletions .browserslistrc
Original file line number Diff line number Diff line change
@@ -1,28 +1,25 @@
[modern]
# Support for dynamic import is the main litmus test for serving modern builds.
# Although officially a ES2020 feature, browsers implemented it early, so this
# enables all of ES2017 and some features in ES2018.
supports es6-module-dynamic-import

# Exclude Safari 11-12 because of a bug in tagged template literals
# https://bugs.webkit.org/show_bug.cgi?id=190756
# Note: Dropping version 11 also enables several more ES2018 features
not Safari < 13
not iOS < 13

# Exclude KaiOS, QQ, and UC browsers due to lack of sufficient feature support data
# Babel ignores these automatically, but we need here for Webpack to output ESM with dynamic imports
# Modern builds target recent browsers supporting the latest features to minimize transpilation, polyfills, etc.
# It is served to browsers meeting the following requirements:
# - released in the last year + current alpha/beta versions
# - Firefox extended support release (ESR)
# - with global utilization at or above 0.5%
# - must support dynamic import of ES modules
# - exclude browsers no longer being maintained
# - exclude KaiOS, QQ, and UC browsers due to lack of sufficient feature support data
unreleased versions
last 1 year
Firefox ESR
>= 0.5% and supports es6-module-dynamic-import
not dead
not KaiOS > 0
not QQAndroid > 0
not UCAndroid > 0

# Exclude unsupported browsers
not dead

[legacy]
# Legacy builds are served when modern requirements are not met and support browsers:
# - released in the last 7 years + current alpha/beta versionss
# - with global utilization above 0.05%
# - with global utilization at or above 0.05%
# The lattermost query ensures that support for popular old browsers is not dropped too early
# (e.g. IE 11, Android 4.4, or Samsung 4).
#
Expand All @@ -36,10 +33,10 @@ not dead
# As of May 2023, only web sockets must be added to the query.
unreleased versions
last 7 years
> 0.05% and supports websockets
>= 0.05% and supports websockets

[legacy-sw]
# Same as legacy plus supports service workers
unreleased versions
last 7 years
> 0.05% and supports websockets and supports serviceworkers
>= 0.05% and supports websockets and supports serviceworkers
10 changes: 8 additions & 2 deletions build-scripts/bundle.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,14 @@ module.exports.babelOptions = ({
"@babel/plugin-transform-runtime",
{ version: dependencies["@babel/runtime"] },
],
// Support some proposals still in TC39 process
["@babel/plugin-proposal-decorators", { decoratorsBeforeExport: true }],
// Transpile decorators (still in TC39 process)
// Modern browsers support class fields and private methods, but transform is required with the older decorator version dictated by Lit
[
"@babel/plugin-proposal-decorators",
{ version: "2018-09", decoratorsBeforeExport: true },
],
"@babel/plugin-transform-class-properties",
"@babel/plugin-transform-private-methods",
].filter(Boolean),
exclude: [
// \\ for Windows, / for Mac OS and Linux
Expand Down
7 changes: 7 additions & 0 deletions build-scripts/gulp/entry-html.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// Tasks to generate entry HTML

import { getUserAgentRegex } from "browserslist-useragent-regexp";
steverep marked this conversation as resolved.
Show resolved Hide resolved
import fs from "fs-extra";
import gulp from "gulp";
import { minify } from "html-minifier-terser";
Expand All @@ -17,6 +18,12 @@ const renderTemplate = (templateFile, data = {}) => {
...data,
useRollup: env.useRollup(),
useWDS: env.useWDS(),
modernRegex: getUserAgentRegex({
env: "modern",
allowHigherVersions: true,
mobileToDesktop: true,
throwOnMissing: true,
}).toString(),
// Resolve any child/nested templates relative to the parent and pass the same data
renderTemplate: (childTemplate) =>
renderTemplate(
Expand Down
8 changes: 1 addition & 7 deletions cast/src/html/faq.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,7 @@
</head>
<body>
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
<script>
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
</script>
<%= renderTemplate("../../../src/html/_script_load_es5.html.template") %>
<%= renderTemplate("../../../src/html/_script_loader.html.template") %>
<hc-layout subtitle="FAQ">
<style>
a {
Expand Down
10 changes: 2 additions & 8 deletions cast/src/html/index.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,9 @@
<%= renderTemplate("_social_meta.html.template") %>
</head>
<body>
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
<hc-connect></hc-connect>
<script>
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
</script>
<%= renderTemplate("../../../src/html/_script_load_es5.html.template") %>
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
<%= renderTemplate("../../../src/html/_script_loader.html.template") %>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
Expand Down
10 changes: 2 additions & 8 deletions cast/src/html/media.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,8 @@
</style>
</head>
<body>
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
<cast-media-player></cast-media-player>
<script>
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
</script>
<%= renderTemplate("../../../src/html/_script_load_es5.html.template") %>
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
<%= renderTemplate("../../../src/html/_script_loader.html.template") %>
</body>
</html>
11 changes: 1 addition & 10 deletions demo/src/html/index.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -83,15 +83,6 @@
<ha-demo></ha-demo>
<%= renderTemplate("../../../src/html/_js_base.html.template") %>
<%= renderTemplate("../../../src/html/_preload_roboto.html.template") %>
<script>
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
if (!isS11_12) {
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
}
</script>
<%= renderTemplate("../../../src/html/_script_load_es5.html.template") %>
<%= renderTemplate("../../../src/html/_script_loader.html.template") %>
</body>
</html>
10 changes: 5 additions & 5 deletions hassio/src/entrypoint.js.template
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@
el.src = src;
document.body.appendChild(el);
}
if (/.*Version\/(?:11|12)(?:\.\d+)*.*Safari\//.test(navigator.userAgent)) {
<% for (const entry of es5EntryJS) { %>
loadES5("<%= entry %>");
<% } %>
} else {
if (<%= modernRegex %>.test(navigator.userAgent)) {
try {
<% for (const entry of latestEntryJS) { %>
new Function("import('<%= entry %>')")();
Expand All @@ -17,6 +13,10 @@
<% for (const entry of es5EntryJS) { %>
loadES5("<%= entry %>");
<% } %>
} else {
<% for (const entry of es5EntryJS) { %>
loadES5("<%= entry %>");
<% } %>
}
}
})();
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,7 @@
"@web/dev-server-rollup": "0.4.1",
"babel-loader": "9.1.3",
"babel-plugin-template-html-minifier": "4.1.0",
"browserslist-useragent-regexp": "4.1.3",
"chai": "5.1.1",
"del": "7.1.0",
"eslint": "8.57.0",
Expand Down
9 changes: 5 additions & 4 deletions src/html/_js_base.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
) {
_ls("/static/polyfills/webcomponents-bundle.js", true);
}
var isS11_12 =
/(?:.*(?:iPhone|iPad).*OS (?:11|12)_\d)|(?:.*Version\/(?:11|12)(?:\.\d+)*.*Safari\/)/.test(
navigator.userAgent
);
// Modern browsers are detected primarily using the user agent string.
// A feature detection which roughly lines up with the modern targets is used
// as a fallback to guard against spoofs. It should be updated periodically.
var isModern = <%= modernRegex %>.test(navigator.userAgent) &&
"findLast" in Array.prototype;
steverep marked this conversation as resolved.
Show resolved Hide resolved
</script>
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
<script <% if (!useWDS) { %>crossorigin="use-credentials"<% } %>>
steverep marked this conversation as resolved.
Show resolved Hide resolved
if (isModern) {
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
}
</script>
<script>
(function() {
if (!window.latestJS) {
Expand Down
9 changes: 2 additions & 7 deletions src/html/authorize.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -52,18 +52,13 @@
</div>
<%= renderTemplate("_js_base.html.template") %>
<%= renderTemplate("_preload_roboto.html.template") %>
<%= renderTemplate("_script_loader.html.template") %>
<script crossorigin="use-credentials">
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
if (!isS11_12) {
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
if (window.latestJS) {
window.providersPromise = fetch("/auth/providers", {
credentials: "same-origin",
});
}
</script>
<%= renderTemplate("_script_load_es5.html.template") %>
</body>
</html>
3 changes: 1 addition & 2 deletions src/html/index.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,7 @@
<%= renderTemplate("_js_base.html.template") %>
<%= renderTemplate("_preload_roboto.html.template") %>
<script <% if (!useWDS) { %>crossorigin="use-credentials"<% } %>>
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
if (!isS11_12) {
if (isModern) {
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
Expand Down
9 changes: 2 additions & 7 deletions src/html/onboarding.html.template
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,13 @@
</div>
<%= renderTemplate("_js_base.html.template") %>
<%= renderTemplate("_preload_roboto.html.template") %>
<%= renderTemplate("_script_loader.html.template") %>
<script crossorigin="use-credentials">
// Safari 12 and below does not have a compliant ES2015 implementation of template literals, so we ship ES5
if (!isS11_12) {
<% for (const entry of latestEntryJS) { %>
import("<%= entry %>");
<% } %>
window.latestJS = true;
if (window.latestJS) {
window.stepsPromise = fetch("/api/onboarding", {
credentials: "same-origin",
});
}
</script>
<%= renderTemplate("_script_load_es5.html.template") %>
</body>
</html>
66 changes: 65 additions & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -5605,6 +5605,13 @@ __metadata:
languageName: node
linkType: hard

"argue-cli@npm:^2.1.0":
version: 2.1.0
resolution: "argue-cli@npm:2.1.0"
checksum: 10/0b300fa171895ad8856513a29320ff3db729637f0dcf0ff2e67a2991190d69d3eb08bc9318956e4bae42b0b6e2c8761b6929364c24640cadd12b5f04a4328a06
languageName: node
linkType: hard

"aria-query@npm:^5.1.3":
version: 5.3.0
resolution: "aria-query@npm:5.3.0"
Expand Down Expand Up @@ -6051,6 +6058,24 @@ __metadata:
languageName: node
linkType: hard

"browserslist-useragent-regexp@npm:4.1.3":
version: 4.1.3
resolution: "browserslist-useragent-regexp@npm:4.1.3"
dependencies:
argue-cli: "npm:^2.1.0"
easy-table: "npm:^1.2.0"
picocolors: "npm:^1.0.0"
regexp-tree: "npm:^0.1.24"
ua-regexes-lite: "npm:^1.2.1"
peerDependencies:
browserslist: ">=4.0.0"
bin:
bluare: dist/cli.js
browserslist-useragent-regexp: dist/cli.js
checksum: 10/f774feb5a766a0b2469c38b5a9f257213375ce106b7d50640ee529cea9c17b91da0f55c4f029fd1e075c8b846fa38cee6feb5620ea1a09f099bb0da61a7950eb
languageName: node
linkType: hard

"browserslist@npm:^4.21.10, browserslist@npm:^4.23.0, browserslist@npm:^4.23.1":
version: 4.23.2
resolution: "browserslist@npm:4.23.2"
Expand Down Expand Up @@ -6950,7 +6975,7 @@ __metadata:
languageName: node
linkType: hard

"defaults@npm:^1.0.4":
"defaults@npm:^1.0.3, defaults@npm:^1.0.4":
version: 1.0.4
resolution: "defaults@npm:1.0.4"
dependencies:
Expand Down Expand Up @@ -7173,6 +7198,19 @@ __metadata:
languageName: node
linkType: hard

"easy-table@npm:^1.2.0":
version: 1.2.0
resolution: "easy-table@npm:1.2.0"
dependencies:
ansi-regex: "npm:^5.0.1"
wcwidth: "npm:^1.0.1"
dependenciesMeta:
wcwidth:
optional: true
checksum: 10/0d1be7cd9419cd1b56ca5a978646b3cff241ccd8cf95bdb2742f36854084b3aef2e9af6ec14142855aa80e4cab1f4baad0f610a99c77509f23676b8330730177
languageName: node
linkType: hard

"ee-first@npm:1.1.1":
version: 1.1.1
resolution: "ee-first@npm:1.1.1"
Expand Down Expand Up @@ -9017,6 +9055,7 @@ __metadata:
app-datepicker: "npm:5.1.1"
babel-loader: "npm:9.1.3"
babel-plugin-template-html-minifier: "npm:4.1.0"
browserslist-useragent-regexp: "npm:4.1.3"
chai: "npm:5.1.1"
chart.js: "npm:4.4.3"
color-name: "npm:2.0.0"
Expand Down Expand Up @@ -12435,6 +12474,15 @@ __metadata:
languageName: node
linkType: hard

"regexp-tree@npm:^0.1.24":
version: 0.1.27
resolution: "regexp-tree@npm:0.1.27"
bin:
regexp-tree: bin/regexp-tree
checksum: 10/08c70c8adb5a0d4af1061bf9eb05d3b6e1d948c433d6b7008e4b5eb12a49429c2d6ca8e9106339a432aa0d07bd6e1bccc638d8f4ab0d045f3adad22182b300a2
languageName: node
linkType: hard

"regexp.prototype.flags@npm:^1.5.2":
version: 1.5.2
resolution: "regexp.prototype.flags@npm:1.5.2"
Expand Down Expand Up @@ -14326,6 +14374,13 @@ __metadata:
languageName: node
linkType: hard

"ua-regexes-lite@npm:^1.2.1":
version: 1.2.1
resolution: "ua-regexes-lite@npm:1.2.1"
checksum: 10/3545a3bd0bedc5a66912b5ba8248a230f0f31f6f6446dd0fa83f7bf77a5e9b206122ab30a8c4b1150bb5ffe5407da8d3b7a557adfa542c0af6bae5ebd77dd703
languageName: node
linkType: hard

"unbox-primitive@npm:^1.0.2":
version: 1.0.2
resolution: "unbox-primitive@npm:1.0.2"
Expand Down Expand Up @@ -14744,6 +14799,15 @@ __metadata:
languageName: node
linkType: hard

"wcwidth@npm:^1.0.1":
version: 1.0.1
resolution: "wcwidth@npm:1.0.1"
dependencies:
defaults: "npm:^1.0.3"
checksum: 10/182ebac8ca0b96845fae6ef44afd4619df6987fe5cf552fdee8396d3daa1fb9b8ec5c6c69855acb7b3c1231571393bd1f0a4cdc4028d421575348f64bb0a8817
languageName: node
linkType: hard

"web-component-analyzer@npm:^2.0.0":
version: 2.0.0
resolution: "web-component-analyzer@npm:2.0.0"
Expand Down
Loading