Skip to content

Commit

Permalink
Redefine browser requirements for modern (latest) builds (#16506)
Browse files Browse the repository at this point in the history
* Redefine browser requirements for modern (latest) builds

* Rename babel class properties plugin

* Fix only allowing latest Android

* Add browsers released in last year

* Use at or above for utilization (no change to browsers currently)

* Only use time query (no effective change)

* Add transform for private methods

* Fix some typos in browserslist config

Co-authored-by: Quentame <[email protected]>

* bump browserslist-useragent-regex

* Add fallback feature detection for Array.prototype.findLast

---------

Co-authored-by: Quentame <[email protected]>
  • Loading branch information
steverep and Quentame authored Jul 19, 2024
1 parent d94d5f9 commit 345000a
Show file tree
Hide file tree
Showing 15 changed files with 126 additions and 80 deletions.
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";
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;
</script>
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
<script <% if (!useWDS) { %>crossorigin="use-credentials"<% } %>>
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

0 comments on commit 345000a

Please sign in to comment.