From d3c9a2175cc416eeb8ddae79ff2fe3faf46a9c39 Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Thu, 12 Nov 2026 13:49:25 -0700 Subject: [PATCH 1/3] Record the supported browser floor: Firefox ESR and Safari 15.6 (fix #502) Nothing said which browsers the site supports, so reviews fell back on Vite's default build target. Set build.target to the floor and document it in CONTRIBUTING.md and AGENTS.md, including that Vite rewrites syntax but adds no polyfills, so newer built-in methods need checking by hand. --- AGENTS.md | 1 + CONTRIBUTING.md | 14 ++++++++++++++ vite.config.mjs | 5 +++++ 3 files changed, 20 insertions(+) diff --git a/AGENTS.md b/AGENTS.md index 758ea97..209bcbd 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,6 +62,7 @@ MozMEAO is taking this repo over. Before that work started there were 810 commit - **CI and CD both run on GitHub Actions.** `.github/workflows/ci.yml` runs lint, a production build (`npm run build`, not browser-tested; it also compiles the Stylus the unit tests import), the Vitest unit tests, and the Playwright end-to-end tests on every push to `main` and every pull request. The Playwright specs run twice: on recorded data in "End-to-end tests", which the `main` ruleset requires along with "Lint and test", and on live data in "Live data tests", which it doesn't. `ssdlc-actions.yml` (zizmor and Semgrep into code scanning) and `sbom.yml` (a CycloneDX SBOM per commit on `main` and per release) call Mozilla's shared reusable workflows in `mozilla/ssdlc-actions`, pinned by SHA; keep the pin in step with bedrock's. There is no `.circleci/`, `Dockerfile`, `docker-compose`, or `Jenkinsfile` — earlier automation was deliberately removed: CircleCI disabled 2018-02-22 (`433a465`), Docker/Dockerflow removed 2018-08-23 (`d3bb561`), `.github/dependabot.yml` deleted 2020-07-29 (`7c7006f`, "Disable non-security updates from Dependabot"). Dependabot came back in #453: `.github/dependabot.yml` groups updates, waits out a 7-day cooldown, and holds back the majors it lists, with reasons. - **The deploy is a static build on Google Cloud Storage** (confirmed by `x-goog-*` headers on the live site). `https://data.firefox.com/version.json` reports `1.2.1` / commit `f655559`, so **prod predates the Vite toolchain on `main`**; no Vite build has reached prod yet, though stage serves one from every push to `main`. `.github/workflows/deploy.yml` deploys `main` to stage and GitHub releases to prod, via Workload Identity (no secrets). The bucket is shared with the transposer's `datasets/`, nothing in the deploy deletes, and deep links only work because `index.html` is copied to each route path. `docs/architecture/deploy.md` records the buckets, CDN, access, and open questions — read it before changing anything about hosting or the workflow. - **Node 24.** `.nvmrc` holds `24` and `engines` requires `^24.15.0`. A plain `npm install` works with no flags. +- **Browser floor: current Firefox ESR and Safari 15.6**, recorded in `build.target` in `vite.config.mjs`. Vite rewrites syntax but adds no polyfills, so check any built-in method newer than Safari 15.6 against MDN before using it in `src/` (`Array.prototype.toSorted` needs Safari 16). See "Supported browsers" in CONTRIBUTING.md. - **A fresh clone will not render styles until you compile Stylus.** `src/components/views/css/*` is gitignored and most views do a side-effect `import './css/Foo.css';` — run `npm run build:css` or the app, and Vitest, fail to resolve those imports. `npm start` compiles it for you. - Open issues date back to 2018, and many predate the toolchain replacement. Check an old issue against the current code before working on it. - Upstream data is **live and current** — transposer `dates` arrays are sorted newest-first and are updated weekly. The app is unmaintained; the data is not. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9abba2f..fd1842b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -94,6 +94,20 @@ style is not enforced (there is no `quotes` rule) — single quotes by conventio directory is excluded via the config's own `ignores` array (flat config's replacement for `.eslintignore`, which no longer exists). +## Supported browsers + +The floor is **the current Firefox ESR and Safari 15.6** (iOS Safari too). Chrome and Edge have no +floor of their own; the build keeps Vite's default of version 111 for them. + +`build.target` in `vite.config.mjs` records the floor, but it only tells Vite which syntax to +rewrite. Vite adds no polyfills, so a built-in method newer than the floor ships as-is and throws +on older browsers. Before using a newer built-in, check its browser compatibility table on MDN. For +example, `Array.prototype.toSorted` needs Safari 16, so sort a copy instead +(`[...points].sort(...)`). Test code under `tests/` runs in Node and Playwright's browsers, not the +floor, so this doesn't apply there. + +When a new Firefox ESR ships, raise `firefox` in `build.target` to match. + ## Styling: Stylus, outside webpack `src/components/views/styl/*.styl` compiles to `src/components/views/css/*.css` via the `stylus` diff --git a/vite.config.mjs b/vite.config.mjs index 3572a17..1116fc4 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -9,6 +9,11 @@ export default defineConfig({ }, build: { outDir: 'build', + // The supported browser floor: current Firefox ESR and Safari 15.6. + // Chrome and Edge keep Vite 8's default. Vite only rewrites syntax for + // these; it adds no polyfills, so new built-in methods must be checked + // by hand. See "Supported browsers" in CONTRIBUTING.md. + target: ['firefox153', 'safari15.6', 'ios15.6', 'chrome111', 'edge111'], }, test: { // Scope to the unit tests only - Vitest's default glob also matches From 64ee30fa4a8599c22a14fd49564e646777cbcef6 Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Thu, 12 Nov 2026 13:53:03 -0700 Subject: [PATCH 2/3] Support the current and previous major of each browser (#502) Replace the Firefox ESR and Safari 15.6 floors with the current and previous major of Chrome, Edge, Firefox, Safari and iOS Safari, and explain why build.target can lag behind them safely. --- AGENTS.md | 2 +- CONTRIBUTING.md | 23 ++++++++++++----------- vite.config.mjs | 10 +++++----- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 209bcbd..82d5685 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,7 +62,7 @@ MozMEAO is taking this repo over. Before that work started there were 810 commit - **CI and CD both run on GitHub Actions.** `.github/workflows/ci.yml` runs lint, a production build (`npm run build`, not browser-tested; it also compiles the Stylus the unit tests import), the Vitest unit tests, and the Playwright end-to-end tests on every push to `main` and every pull request. The Playwright specs run twice: on recorded data in "End-to-end tests", which the `main` ruleset requires along with "Lint and test", and on live data in "Live data tests", which it doesn't. `ssdlc-actions.yml` (zizmor and Semgrep into code scanning) and `sbom.yml` (a CycloneDX SBOM per commit on `main` and per release) call Mozilla's shared reusable workflows in `mozilla/ssdlc-actions`, pinned by SHA; keep the pin in step with bedrock's. There is no `.circleci/`, `Dockerfile`, `docker-compose`, or `Jenkinsfile` — earlier automation was deliberately removed: CircleCI disabled 2018-02-22 (`433a465`), Docker/Dockerflow removed 2018-08-23 (`d3bb561`), `.github/dependabot.yml` deleted 2020-07-29 (`7c7006f`, "Disable non-security updates from Dependabot"). Dependabot came back in #453: `.github/dependabot.yml` groups updates, waits out a 7-day cooldown, and holds back the majors it lists, with reasons. - **The deploy is a static build on Google Cloud Storage** (confirmed by `x-goog-*` headers on the live site). `https://data.firefox.com/version.json` reports `1.2.1` / commit `f655559`, so **prod predates the Vite toolchain on `main`**; no Vite build has reached prod yet, though stage serves one from every push to `main`. `.github/workflows/deploy.yml` deploys `main` to stage and GitHub releases to prod, via Workload Identity (no secrets). The bucket is shared with the transposer's `datasets/`, nothing in the deploy deletes, and deep links only work because `index.html` is copied to each route path. `docs/architecture/deploy.md` records the buckets, CDN, access, and open questions — read it before changing anything about hosting or the workflow. - **Node 24.** `.nvmrc` holds `24` and `engines` requires `^24.15.0`. A plain `npm install` works with no flags. -- **Browser floor: current Firefox ESR and Safari 15.6**, recorded in `build.target` in `vite.config.mjs`. Vite rewrites syntax but adds no polyfills, so check any built-in method newer than Safari 15.6 against MDN before using it in `src/` (`Array.prototype.toSorted` needs Safari 16). See "Supported browsers" in CONTRIBUTING.md. +- **Supported browsers: the current and previous major of Chrome, Edge, Firefox, Safari, and iOS Safari.** `build.target` in `vite.config.mjs` records those floors as last checked. Vite rewrites syntax but adds no polyfills, so check a recently added built-in method against MDN before using it in `src/`. See "Supported browsers" in CONTRIBUTING.md. - **A fresh clone will not render styles until you compile Stylus.** `src/components/views/css/*` is gitignored and most views do a side-effect `import './css/Foo.css';` — run `npm run build:css` or the app, and Vitest, fail to resolve those imports. `npm start` compiles it for you. - Open issues date back to 2018, and many predate the toolchain replacement. Check an old issue against the current code before working on it. - Upstream data is **live and current** — transposer `dates` arrays are sorted newest-first and are updated weekly. The app is unmaintained; the data is not. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index fd1842b..ce60952 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,17 +96,18 @@ directory is excluded via the config's own `ignores` array (flat config's replac ## Supported browsers -The floor is **the current Firefox ESR and Safari 15.6** (iOS Safari too). Chrome and Edge have no -floor of their own; the build keeps Vite's default of version 111 for them. - -`build.target` in `vite.config.mjs` records the floor, but it only tells Vite which syntax to -rewrite. Vite adds no polyfills, so a built-in method newer than the floor ships as-is and throws -on older browsers. Before using a newer built-in, check its browser compatibility table on MDN. For -example, `Array.prototype.toSorted` needs Safari 16, so sort a copy instead -(`[...points].sort(...)`). Test code under `tests/` runs in Node and Playwright's browsers, not the -floor, so this doesn't apply there. - -When a new Firefox ESR ships, raise `firefox` in `build.target` to match. +We support the current and previous major version of Chrome, Edge, Firefox, Safari, and iOS +Safari. For Safari, a major version is the yearly number (26, 27), not a point release. + +`build.target` in `vite.config.mjs` records those floors as of the last time someone checked +them. It only tells Vite which syntax to rewrite. Vite adds no polyfills, so a built-in method newer +than the floor ships as-is and throws in older browsers. Before using a recently added built-in, +check its browser compatibility table on MDN against the floor. Test code under `tests/` runs in +Node and Playwright's browsers, so this doesn't apply there. + +Chrome, Edge, and Firefox ship a major version every four weeks, so the numbers in `build.target` +fall behind. That's safe: an older target only makes Vite rewrite a little more than it needs to. +Raise them when you check, but never past the previous major. ## Styling: Stylus, outside webpack diff --git a/vite.config.mjs b/vite.config.mjs index 1116fc4..14e2f10 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -9,11 +9,11 @@ export default defineConfig({ }, build: { outDir: 'build', - // The supported browser floor: current Firefox ESR and Safari 15.6. - // Chrome and Edge keep Vite 8's default. Vite only rewrites syntax for - // these; it adds no polyfills, so new built-in methods must be checked - // by hand. See "Supported browsers" in CONTRIBUTING.md. - target: ['firefox153', 'safari15.6', 'ios15.6', 'chrome111', 'edge111'], + // The oldest supported versions, as last checked in November 2026: the + // current and previous major of each browser. Vite only rewrites + // syntax for these and adds no polyfills. See "Supported browsers" in + // CONTRIBUTING.md. + target: ['chrome156', 'edge156', 'firefox159', 'safari26', 'ios26'], }, test: { // Scope to the unit tests only - Vitest's default glob also matches From f403ce1395390b9faec41588c7128b03941f18b9 Mon Sep 17 00:00:00 2001 From: Stephanie Hobson Date: Thu, 12 Nov 2026 15:38:07 -0700 Subject: [PATCH 3/3] Make Baseline Widely available the browser support policy (#502) A moving, published standard instead of version numbers that need maintaining. build.target becomes Vite's 'baseline-widely-available', and contributors check a feature's Baseline status before using it. --- AGENTS.md | 2 +- CONTRIBUTING.md | 26 ++++++++++++++------------ vite.config.mjs | 10 +++++----- 3 files changed, 20 insertions(+), 18 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index 82d5685..6694292 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -62,7 +62,7 @@ MozMEAO is taking this repo over. Before that work started there were 810 commit - **CI and CD both run on GitHub Actions.** `.github/workflows/ci.yml` runs lint, a production build (`npm run build`, not browser-tested; it also compiles the Stylus the unit tests import), the Vitest unit tests, and the Playwright end-to-end tests on every push to `main` and every pull request. The Playwright specs run twice: on recorded data in "End-to-end tests", which the `main` ruleset requires along with "Lint and test", and on live data in "Live data tests", which it doesn't. `ssdlc-actions.yml` (zizmor and Semgrep into code scanning) and `sbom.yml` (a CycloneDX SBOM per commit on `main` and per release) call Mozilla's shared reusable workflows in `mozilla/ssdlc-actions`, pinned by SHA; keep the pin in step with bedrock's. There is no `.circleci/`, `Dockerfile`, `docker-compose`, or `Jenkinsfile` — earlier automation was deliberately removed: CircleCI disabled 2018-02-22 (`433a465`), Docker/Dockerflow removed 2018-08-23 (`d3bb561`), `.github/dependabot.yml` deleted 2020-07-29 (`7c7006f`, "Disable non-security updates from Dependabot"). Dependabot came back in #453: `.github/dependabot.yml` groups updates, waits out a 7-day cooldown, and holds back the majors it lists, with reasons. - **The deploy is a static build on Google Cloud Storage** (confirmed by `x-goog-*` headers on the live site). `https://data.firefox.com/version.json` reports `1.2.1` / commit `f655559`, so **prod predates the Vite toolchain on `main`**; no Vite build has reached prod yet, though stage serves one from every push to `main`. `.github/workflows/deploy.yml` deploys `main` to stage and GitHub releases to prod, via Workload Identity (no secrets). The bucket is shared with the transposer's `datasets/`, nothing in the deploy deletes, and deep links only work because `index.html` is copied to each route path. `docs/architecture/deploy.md` records the buckets, CDN, access, and open questions — read it before changing anything about hosting or the workflow. - **Node 24.** `.nvmrc` holds `24` and `engines` requires `^24.15.0`. A plain `npm install` works with no flags. -- **Supported browsers: the current and previous major of Chrome, Edge, Firefox, Safari, and iOS Safari.** `build.target` in `vite.config.mjs` records those floors as last checked. Vite rewrites syntax but adds no polyfills, so check a recently added built-in method against MDN before using it in `src/`. See "Supported browsers" in CONTRIBUTING.md. +- **Supported browsers: Baseline Widely available.** Use a web platform feature in `src/` only if MDN or webstatus.dev marks it Baseline Widely available. `build.target` in `vite.config.mjs` is Vite's `'baseline-widely-available'`, which rewrites syntax but adds no polyfills. See "Supported browsers" in CONTRIBUTING.md. - **A fresh clone will not render styles until you compile Stylus.** `src/components/views/css/*` is gitignored and most views do a side-effect `import './css/Foo.css';` — run `npm run build:css` or the app, and Vitest, fail to resolve those imports. `npm start` compiles it for you. - Open issues date back to 2018, and many predate the toolchain replacement. Check an old issue against the current code before working on it. - Upstream data is **live and current** — transposer `dates` arrays are sorted newest-first and are updated weekly. The app is unmaintained; the data is not. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index ce60952..f2d1624 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,18 +96,20 @@ directory is excluded via the config's own `ignores` array (flat config's replac ## Supported browsers -We support the current and previous major version of Chrome, Edge, Firefox, Safari, and iOS -Safari. For Safari, a major version is the yearly number (26, 27), not a point release. - -`build.target` in `vite.config.mjs` records those floors as of the last time someone checked -them. It only tells Vite which syntax to rewrite. Vite adds no polyfills, so a built-in method newer -than the floor ships as-is and throws in older browsers. Before using a recently added built-in, -check its browser compatibility table on MDN against the floor. Test code under `tests/` runs in -Node and Playwright's browsers, so this doesn't apply there. - -Chrome, Edge, and Firefox ship a major version every four weeks, so the numbers in `build.target` -fall behind. That's safe: an older target only makes Vite rewrite a little more than it needs to. -Raise them when you check, but never past the previous major. +We support browsers that are [Baseline Widely available](https://web.dev/baseline): the versions +of Chrome, Edge, Firefox, and Safari, on desktop and mobile, that support every feature that has +worked in all of them for at least 30 months. The floor moves forward on its own. To see today's +versions, run `npx browserslist "baseline widely available"`. + +Use a web platform feature only if MDN or [webstatus.dev](https://webstatus.dev) marks it Baseline +Widely available. A feature marked Newly available works in the latest browsers but not yet in all +the supported ones. + +`build.target` in `vite.config.mjs` is Vite's `'baseline-widely-available'`. Vite fixes the +versions that means at each major release, so they lag behind the policy. That is the safe +direction: Vite rewrites a little more syntax than it needs to. Vite adds no polyfills, so a +built-in method outside the policy ships as-is and throws in older browsers. Test code under +`tests/` runs in Node and Playwright's browsers, so the policy doesn't apply there. ## Styling: Stylus, outside webpack diff --git a/vite.config.mjs b/vite.config.mjs index 14e2f10..c761d80 100644 --- a/vite.config.mjs +++ b/vite.config.mjs @@ -9,11 +9,11 @@ export default defineConfig({ }, build: { outDir: 'build', - // The oldest supported versions, as last checked in November 2026: the - // current and previous major of each browser. Vite only rewrites - // syntax for these and adds no polyfills. See "Supported browsers" in - // CONTRIBUTING.md. - target: ['chrome156', 'edge156', 'firefox159', 'safari26', 'ios26'], + // Our browser support policy is Baseline Widely available. Vite fixes + // the versions this means at each major release, so they lag behind + // the policy, which is the safe direction. Vite only rewrites syntax + // and adds no polyfills. See "Supported browsers" in CONTRIBUTING.md. + target: 'baseline-widely-available', }, test: { // Scope to the unit tests only - Vitest's default glob also matches