Pin the Baseline date in .browserslistrc

What does this MR do and why?

Makes the compiled frontend assets a function of the source again, instead of the day they are compiled:

  1. Pins .browserslistrc to baseline widely available on 2026-10-01.
  2. Adds .browserslistrc to the assets cache key in scripts/lib/assets_sha.rb.
  3. Adds Keeps::UpdateBrowserslistBaselineDate, a monthly housekeeper keep that moves the date to the first day of the current month through a reviewed MR.

The problem

.browserslistrc contains the bare query baseline widely available. For that form, browserslist calls getCompatibleVersions() without a date (index.js#L821-L866 at 4.28.5), and baseline-browser-mapping uses new Date() minus 30 months as the cutoff. The resolved browsers drive Babel preset-env with useBuiltIns: 'usage' (so the core-js polyfill set, babel.config.js), the SWC env.targets in config/rspack/loader_rules.js, and autoprefixer (postcss.config.js).

Resolved with the lockfile versions (browserslist 4.28.5, baseline-browser-mapping 2.10.42, caniuse-lite 1.0.30001803, core-js-compat 3.38.0, corejs.version 3.45.1), the same source targets these browsers depending on the build day (UTC):

Build day Chrome / Edge Firefox Safari / iOS Safari core-js polyfills
2026-07-25 to 2026-08-19 121 122 17.2 188
2026-08-20 to 2026-09-04 121 123 17.2 188
2026-09-05 to 2026-09-18 121 123 17.4 184
2026-09-19 to 2026-09-21 121 124 17.4 184
2026-09-22 to 2026-10-15 123 124 17.4 183
2026-10-16 to 2026-10-17 123 125 17.4 183
2026-10-18 to 2026-11-12 124 125 17.4 183

The CI asset cache hides this most of the time, but every recompilation picks up the current day. A patch release compiled weeks after the first release of a version can drop polyfills that the version shipped with. baseline-browser-mapping itself recommends pinning the date per build (README, "Keeping baseline-browser-mapping up to date"), and browserslist documents the dated form (README).

Why 2026-10-01

It resolves to the same 115 browsers and the same 183 core-js polyfills as the undated query on 2026-10-12, so merging changes nothing in the compiled output. Every date from 2026-09-22 to 2026-10-15 resolves to that set. If this merges after 2026-10-15, the pin is still deterministic, but it holds the browser set at the 2026-10-01 level, while an undated build would already have moved on, until the keep's November MR.

Babel preset-env 7.23.7 and autoprefixer 10.4.14 produce byte-identical output for the old and the new .browserslistrc on a sample that uses polyfillable APIs (Array#at, Promise.withResolvers, ArrayBuffer#transfer, Set#union, and others) and prefixable CSS. The same sample with on 2026-08-01 produces 29 instead of 27 core-js imports, so the comparison does detect a change.

Why the cache key changes

.assets-compilation-patterns in .gitlab/ci/rules.gitlab-ci.yml already lists .browserslistrc, and scripts/lib/assets_sha.rb says that its list should match, but AssetsSha did not hash the file. The .assets-cache key and the assets image tag both come from that hash, and scripts/compile_assets skips compilation on a cache hit. Without this change, a commit that only moves the date would reuse assets compiled for the previous browser set.

Keeping the date current

The keep follows the existing pattern for scheduled keeps in .gitlab/ci/housekeeping.gitlab-ci.yml, like the monthly frontend keep Keeps::CleanupGlIntroduced. It sets the first day of the current month, so every run in a month produces the same change and a rerun updates the open MR. It does nothing when the pinned date is already that day or later, or when the query has no date. Every month reuses the same branch, so the keep overrides recreate_when_closed? (like Keeps::RubocopFixer): closing one month's MR does not stop the following months. It asks a maintainer::frontend reviewer, because moving the date changes the shipped browser support.

Alternatives considered:

  • A Renovate custom manager: the Renovate configuration for this project lives outside it, in gitlab-org/frontend/renovate-gitlab-bot (doc/development/dependencies.md), and the date is not a version of any package.
  • A spec that fails when the date is older than N months: it would break master on a day unrelated to any change.
  • Deriving the date from the commit date during the build: GitLab compiles assets in several places (CI, Omnibus, CNG, gitlab:assets:compile on source installations), and not all of them have Git metadata. A date in the file works everywhere.

Consumers of the query

Consumer How it reads .browserslistrc Result with the dated query
config/rspack/loader_rules.js (SWC env.targets) browserslist(browserslist.loadConfig({ path: ROOT_PATH })) Same 115 browsers
babel.config.js (@babel/preset-env) @babel/helper-compilation-targets 7.27.2, browserslist config Identical output
postcss.config.js (autoprefixer) browserslist config Identical output
config/helpers/supported_browsers.js SHA-256 of the file content One-time miss of the webpack babel-loader and Rspack persistent caches, as intended
config/rspack.config.mjs target: 'web', so Rspack does not resolve browserslist itself Not affected
vite.config.js lightningcss with errorRecovery only; PostCSS as above Not affected
doc/install/requirements.md Describes the Widely available set, does not quote the query Still accurate, no change

browserslist added both the bare and the dated Baseline forms in 4.26.0, and yarn.lock resolves every browserslist range to 4.28.5, so no consumer can understand one form but not the other.

Known limitation

baseline-browser-mapping parses the date as UTC midnight but subtracts the 30 months in local time. Comparing every day from 2025-01-01 to 2027-12-31 in six time zones against UTC, 54 of 1095 dates resolve to a slightly different set in at least one of them. 2026-10-01 and the monthly dates from 2026-11-01 to 2027-08-01 are not affected. CI compiles in UTC. This could be reported upstream to web-platform-dx/baseline-browser-mapping.

References

Screenshots or screen recordings

Not applicable: build configuration only, no UI change.

How to set up and validate locally

  1. On master and on this branch, compare the resolved browsers. Until 2026-10-15 both print the same list:

    yarn browserslist
  2. See how the set depends on the date:

    yarn browserslist "baseline widely available on 2026-08-01"
    yarn browserslist "baseline widely available on 2026-10-01"
  3. Dry-run the keep. In October 2026 it makes no change, because the date is already 2026-10-01. To see a change, first set an older date in .browserslistrc and commit it, then run:

    bundle exec gitlab-housekeeper -d -k Keeps::UpdateBrowserslistBaselineDate

    The dry run commits the change to a local branch and prints the MR it would open. It does not push.

Post-merge

Create a pipeline schedule on the default branch with SCHEDULE_TYPE=housekeeping and HOUSEKEEPING_KEEP=update_browserslist_baseline_date, and a monthly cron early in the month (for example 0 6 2 * *), as described at the top of .gitlab/ci/housekeeping.gitlab-ci.yml. HOUSEKEEPER_GITLAB_API_TOKEN is already required by the other housekeeping jobs.

MR acceptance checklist

Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

Merge request reports

Loading
Loading