Skip to content

Update .browserslistrc to use Baseline #30036

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

Merged
merged 4 commits into from
Apr 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .bazelignore
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ packages/ngtools/webpack/node_modules
packages/schematics/angular/node_modules
modules/testing/builder/node_modules
tests/node_modules
tools/baseline_browserslist/node_modules
tools/legacy-rnjs/node_modules
1 change: 1 addition & 0 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ npm_translate_lock(
"//packages/ngtools/webpack:package.json",
"//packages/schematics/angular:package.json",
"//tests:package.json",
"//tools/baseline_browserslist:package.json",
],
lifecycle_hooks_envs = {
# TODO: Standardize browser management for `rules_js`
Expand Down
7 changes: 7 additions & 0 deletions constants.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,13 @@ ANGULAR_FW_VERSION = "^20.0.0-next.0"
ANGULAR_FW_PEER_DEP = "^20.0.0 || ^20.0.0-next.0"
NG_PACKAGR_PEER_DEP = "^20.0.0 || ^20.0.0-next.0"

# Baseline widely-available date in `YYYY-MM-DD` format which defines Angular's
# browser support. This date serves as the source of truth for the Angular CLI's
# default browser set used to determine what downleveling is necessary.
#
# See: https://web.dev/baseline
BASELINE_DATE = "2025-03-31"

SNAPSHOT_REPOS = {
"@angular/cli": "angular/cli-builds",
"@angular/pwa": "angular/angular-pwa-builds",
Expand Down
31 changes: 31 additions & 0 deletions docs/process/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,34 @@ will block the next weekly release.
accept the invite for the new package.

Once Wombat accepts the invite, regular automated releases should work as expected.

## Updating Browser Support

Angular's browser support is defined by a [Baseline](https://web.dev/baseline)
"widely available" date. Before a new major version is released, this should be
updated to approximately the current date.

A few weeks before a major (around feature freeze):

1. Update `BASELINE_DATE` in
[`/constants.bzl`](/constants.bzl) to the end of the most recent month.
- For example, if it is currently May 12th, set `baselineThreshold` to April
30th.
- Picking a date at the end of a month makes it easier to cross-reference
Angular's support with other tools (like MDN) which state Baseline support
using month specificity.
- You can view the generated `browserlist` configuration with:
```shell
bazel build //packages/angular/build:angular_browserslist
cat dist/bin/packages/angular/build/.browserslistrc
```
- Commit and merge the change, no other alterations or automation is
necessary in the CLI repo.
2. Update
[`/.browserslistrc`](https://github.com/ng-packagr/ng-packagr/tree/main/.browserslistrc)
in the `ng-packagr` repo.
- Use the generated configuration from above.
3. Update
[`angular.dev` documentation](https://github.com/angular/angular/tree/main/adev/src/content/reference/versions.md#browser-support)
to specify the date used and link to [browsersl.ist](https://browsersl.ist)
with the generated configuration.

This file was deleted.

9 changes: 9 additions & 0 deletions packages/angular/build/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
load("@devinfra//bazel/api-golden:index_rjs.bzl", "api_golden_test_npm_package")
load("@npm2//:defs.bzl", "npm_link_all_packages")
load("//:constants.bzl", "BASELINE_DATE")
load("//tools:defaults.bzl", "copy_to_bin", "jasmine_test", "npm_package", "ts_project")
load("//tools:ts_json_schema.bzl", "ts_json_schema")
load("//tools/baseline_browserslist:baseline_browserslist.bzl", "baseline_browserslist")

licenses(["notice"])

Expand Down Expand Up @@ -39,6 +41,12 @@ copy_to_bin(
srcs = glob(["**/schema.json"]),
)

baseline_browserslist(
name = "angular_browserslist",
out = ".browserslistrc",
baseline = BASELINE_DATE,
)

RUNTIME_ASSETS = glob(
include = [
"src/**/schema.json",
Expand All @@ -49,6 +57,7 @@ RUNTIME_ASSETS = glob(
) + [
"builders.json",
"package.json",
":angular_browserslist",
]

ts_project(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,12 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
});

it('warns when IE is present in browserslist', async () => {
await harness.appendToFile(
await harness.writeFile(
'.browserslistrc',
`
IE 9
IE 11
`,
IE 9
IE 11
`,
);

harness.useTarget('build', {
Expand All @@ -102,10 +102,30 @@ describeBuilder(buildApplication, APPLICATION_BUILDER_INFO, (harness) => {
expect(logs).toContain(
jasmine.objectContaining({
level: 'warn',
message:
`One or more browsers which are configured in the project's Browserslist ` +
'configuration will be ignored as ES5 output is not supported by the Angular CLI.\n' +
'Ignored browsers: ie 11, ie 9',
message: jasmine.stringContaining('ES5 output is not supported'),
}),
);

// Don't duplicate the error.
expect(logs).not.toContain(
jasmine.objectContaining({
message: jasmine.stringContaining("fall outside Angular's browser support"),
}),
);
});

it("warns when targeting a browser outside Angular's minimum support", async () => {
await harness.writeFile('.browserslistrc', 'Chrome >= 100');

harness.useTarget('build', BASE_OPTIONS);

const { result, logs } = await harness.executeOnce();
expect(result?.success).toBeTrue();

expect(logs).toContain(
jasmine.objectContaining({
level: 'warn',
message: jasmine.stringContaining("fall outside Angular's browser support"),
}),
);
});
Expand Down
36 changes: 25 additions & 11 deletions packages/angular/build/src/utils/supported-browsers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,35 +12,49 @@ export function getSupportedBrowsers(
projectRoot: string,
logger: { warn(message: string): void },
): string[] {
browserslist.defaults = [
'last 2 Chrome versions',
'last 1 Firefox version',
'last 2 Edge major versions',
'last 2 Safari major versions',
'last 2 iOS major versions',
'last 2 Android major versions',
'Firefox ESR',
];
// Read the browserslist configuration containing Angular's browser support policy.
const angularBrowserslist = browserslist(undefined, {
path: require.resolve('../../.browserslistrc'),
});

// Use Angular's configuration as the default.
browserslist.defaults = angularBrowserslist;

// Get the minimum set of browser versions supported by Angular.
const minimumBrowsers = new Set(angularBrowserslist);

// Get browsers from config or default.
const browsersFromConfigOrDefault = new Set(browserslist(undefined, { path: projectRoot }));

// Get browsers that support ES6 modules.
const browsersThatSupportEs6 = new Set(browserslist('supports es6-module'));

const nonEs6Browsers: string[] = [];
const unsupportedBrowsers: string[] = [];
for (const browser of browsersFromConfigOrDefault) {
if (!browsersThatSupportEs6.has(browser)) {
// Any browser which does not support ES6 is explicitly ignored, as Angular will not build successfully.
browsersFromConfigOrDefault.delete(browser);
nonEs6Browsers.push(browser);
} else if (!minimumBrowsers.has(browser)) {
// Any other unsupported browser we will attempt to use, but provide no support for.
unsupportedBrowsers.push(browser);
}
}

if (unsupportedBrowsers.length) {
if (nonEs6Browsers.length) {
logger.warn(
`One or more browsers which are configured in the project's Browserslist configuration ` +
'will be ignored as ES5 output is not supported by the Angular CLI.\n' +
`Ignored browsers: ${unsupportedBrowsers.join(', ')}`,
`Ignored browsers:\n${nonEs6Browsers.join(', ')}`,
);
}

if (unsupportedBrowsers.length) {
logger.warn(
`One or more browsers which are configured in the project's Browserslist configuration ` +
"fall outside Angular's browser support for this version.\n" +
`Unsupported browsers:\n${unsupportedBrowsers.join(', ')}`,
);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,12 @@ describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
});

it('warns when IE is present in browserslist', async () => {
await harness.appendToFile(
await harness.writeFile(
'.browserslistrc',
`
IE 9
IE 11
`,
IE 9
IE 11
`,
);

harness.useTarget('build', {
Expand All @@ -83,10 +83,30 @@ describeBuilder(buildWebpackBrowser, BROWSER_BUILDER_INFO, (harness) => {
expect(logs).toContain(
jasmine.objectContaining({
level: 'warn',
message:
`One or more browsers which are configured in the project's Browserslist ` +
'configuration will be ignored as ES5 output is not supported by the Angular CLI.\n' +
'Ignored browsers: ie 11, ie 9',
message: jasmine.stringContaining('ES5 output is not supported'),
}),
);

// Don't duplicate the error.
expect(logs).not.toContain(
jasmine.objectContaining({
message: jasmine.stringContaining("fall outside Angular's browser support"),
}),
);
});

it("warns when targeting a browser outside Angular's minimum support", async () => {
await harness.writeFile('.browserslistrc', 'Chrome >= 100');

harness.useTarget('build', BASE_OPTIONS);

const { result, logs } = await harness.executeOnce();
expect(result?.success).toBeTrue();

expect(logs).toContain(
jasmine.objectContaining({
level: 'warn',
message: jasmine.stringContaining("fall outside Angular's browser support"),
}),
);
});
Expand Down
9 changes: 9 additions & 0 deletions packages/schematics/angular/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
# found in the LICENSE file at https://angular.dev/license

load("@npm2//:defs.bzl", "npm_link_all_packages")
load("//:constants.bzl", "BASELINE_DATE")
load("//tools:defaults.bzl", "copy_to_bin", "jasmine_test", "npm_package", "ts_project")
load("//tools:ts_json_schema.bzl", "ts_json_schema")
load("//tools/baseline_browserslist:baseline_browserslist.bzl", "baseline_browserslist")

licenses(["notice"])

Expand Down Expand Up @@ -42,11 +44,18 @@ copy_to_bin(
srcs = glob(["**/schema.json"]),
)

baseline_browserslist(
name = "angular_browserslist",
out = "config/.browserslistrc",
baseline = BASELINE_DATE,
)

RUNTIME_ASSETS = [
"collection.json",
"migrations/migration-collection.json",
"package.json",
"utility/latest-versions/package.json",
":angular_browserslist",
] + glob(
include = [
"*/schema.json",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,10 @@
# For additional information regarding the format and rule options, please see:
# https://github.com/browserslist/browserslist#queries

# For the full list of supported browsers by the Angular framework, please see:
# For Angular's browser support policy, please see:
# https://angular.dev/reference/versions#browser-support

# You can see what browsers were selected by your queries by running:
# npx browserslist

last 2 Chrome versions
last 1 Firefox version
last 2 Edge major versions
last 2 Safari major versions
last 2 iOS major versions
last 2 Android major versions
Firefox ESR
<%= config %>
6 changes: 5 additions & 1 deletion packages/schematics/angular/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
strings,
url,
} from '@angular-devkit/schematics';
import { readFile } from 'node:fs/promises';
import { posix as path } from 'node:path';
import { relativePathToWorkspaceRoot } from '../utility/paths';
import { getWorkspace as readWorkspace, updateWorkspace } from '../utility/workspace';
Expand All @@ -42,10 +43,13 @@ function addBrowserslistConfig(options: ConfigOptions): Rule {
throw new SchematicsException(`Project name "${options.project}" doesn't not exist.`);
}

// Read Angular's default vendored `.browserslistrc` file.
const config = await readFile(path.join(__dirname, '.browserslistrc'), 'utf8');

return mergeWith(
apply(url('./files'), [
filter((p) => p.endsWith('.browserslistrc.template')),
applyTemplates({}),
applyTemplates({ config }),
move(project.root),
]),
);
Expand Down
2 changes: 1 addition & 1 deletion packages/schematics/angular/config/index_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ describe('Config Schematic', () => {
describe(`when 'type' is 'browserslist'`, () => {
it('should create a .browserslistrc file', async () => {
const tree = await runConfigSchematic(ConfigType.Browserslist);
expect(tree.exists('projects/foo/.browserslistrc')).toBeTrue();
expect(tree.readContent('projects/foo/.browserslistrc')).toContain('Chrome >=');
});
});
});
Loading
Loading