Skip to content

build(deps-dev): L3-0000 bump vite to 8 and merge React 19 upgrade - #907

Open
dependabot[bot] wants to merge 16 commits into
mainfrom
dependabot/npm_and_yarn/multi-eebdba2d21
Open

dependabot[bot] wants to merge 16 commits into
mainfrom
dependabot/npm_and_yarn/multi-eebdba2d21

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jul 27, 2026

Copy link
Copy Markdown
Contributor

Jira ticket

L3-0000 (dependabot bundled upgrade)

Screenshots

Before After
n/a (dependency-only + build-config changes) n/a

Figma link

n/a

Summary

Upgrade Vite (7.3.1 → 8.1.5) and @vitejs/plugin-react (5.1.4 → 5.2.0) as dependabot proposed, plus everything else needed to make the tree install and CI pass:

  • Bump the Storybook 10 family (10.2.8 → 10.5.5) so @storybook/react-vite's peer range accepts vite@^8.
  • Merge in chore/react-19-upgrade so @types/react, react, and react-dom land at v19 in the same PR.
  • Fix vite@8 CJS interop for flatpickr's l10n export (l10n.default.en in the browser vs l10n.en in jsdom).
  • Add a sass findFileUrl importer in .storybook/main.ts because vite@8's rolldown-based CSS pipeline stopped applying resolve.alias to @use/@import, which was breaking ~scss/allPartials.
  • Strip stray quotes from var('--…') in _composedModal.scss — lightningcss (vite@8's default CSS minifier) rejects the quoted form.
  • Pin ics and add explicit glob so the fresh lockfile does not regress on latent code paths.

Verified all vite-adjacent plugins (vite-plugin-dts, vite-plugin-svgr, vite-tsconfig-paths, @vitejs/plugin-react, @storybook/{react-vite,builder-vite}) declare peer ranges that include vite@^8; no further plugin bumps required.

Change List (describe the changes made to the files)

  • package.json, package-lock.json: bump vite → 8.1.5, @vitejs/plugin-react → 5.2.0, @storybook/* + eslint-plugin-storybook + storybook-addon-pseudo-states → ^10.5.5, add explicit glob, pin ics, plus the React 19 dep upgrades from chore/react-19-upgrade.
  • .storybook/main.ts: register a sass findFileUrl importer that maps ~scss/* to src/scss/*.
  • src/components/DatePicker/DatePicker.tsx: unwrap the flatpickr/dist/l10n/index default import so both node and vite-bundled browser interop resolve to the locale table.
  • src/components/ComposedModal/_composedModal.scss: remove quotes from var('--max-modal-body-height').
  • Plus the source-level React 19 updates carried in from chore/react-19-upgrade (removed Record<string, unknown> intersections, explicit forwardRef generics, updated useRef initial-value pattern, etc.).

Acceptance Test (how to verify the PR)

  1. npm ci succeeds (no --legacy-peer-deps needed).
  2. npm run build succeeds.
  3. npm test -- --run — 1042/1042 unit tests pass.
  4. npm run test-storybook — 238/238 storybook tests pass.
  5. npm run build:storybook succeeds and produces storybook-static/.
  6. npm run lint is clean.
  7. Netlify preview deploy for this PR succeeds and Storybook renders.

Regression Test

  • Compare Chromatic snapshots against main — visual diffs should be limited to the intentional React 19 surface changes.
  • Spot-check the DatePicker story (opens flatpickr, English weekday shorthand renders) — validates the l10n interop shim in both dev and production builds.
  • Spot-check the ComposedModal story — validates the sass ~scss importer still resolves and the CSS custom property still applies.

Evidence of testing

  • Local npm ci && npm run build && npm test -- --run && npm run test-storybook && npm run build:storybook && npm run lint all pass on macOS with Node 22.
  • The Netlify Deploy Preview job on this PR built the storybook successfully after the sass importer + var() fixes landed.

Things to look for during review

  • PR title should correctly describe the most significant type of commit. I.e. feat(scope): ... if a minor release should be triggered.
  • All commit messages follow convention and are appropriate for the changes
  • All references to phillips class prefix are using the prefix variable
  • All major areas have a data-testid attribute.
  • Document all props with jsdoc comments
  • All strings should be translatable.
  • Unit tests should be written and should have a coverage of 90% or higher in all areas.

Note
Automatic rebases have been disabled on this pull request as it has been open for over 30 days.

@dependabot dependabot Bot added the dependencies Pull requests that update a dependency file label Jul 27, 2026
Copilot AI review requested due to automatic review settings July 27, 2026 17:00
@dependabot dependabot Bot added the javascript Pull requests that update javascript code label Jul 27, 2026
@dependabot dependabot Bot added dependencies Pull requests that update a dependency file javascript Pull requests that update javascript code labels Jul 27, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Note

Copilot could not run the full agentic suite for this review because it was automatically requested on a bot-authored pull request. Request a review from Copilot under Reviewers to retry with the full agentic suite. Improved support for bot-authored pull requests is coming soon.

Updates the Vite toolchain versions in package.json.

Changes:

  • Bumped @vitejs/plugin-react from ^5.1.4 to ^5.2.0
  • Bumped vite from ^7.3.1 to ^8.1.5

Comment thread package.json
"@typescript-eslint/eslint-plugin": "^8.18.0",
"@typescript-eslint/parser": "^8.18.0",
"@vitejs/plugin-react": "^5.1.4",
"@vitejs/plugin-react": "^5.2.0",
Comment thread package.json
"typescript": "^5.5.4",
"typescript-eslint": "^8.18.0",
"vite": "^7.3.1",
"vite": "^8.1.5",
@netlify

netlify Bot commented Jul 27, 2026

Copy link
Copy Markdown

Deploy Preview for phillips-seldon ready!

Name Link
🔨 Latest commit 13026a2
🔍 Latest deploy log https://app.netlify.com/projects/phillips-seldon/deploys/6a68adfa3966ad0008555b9d
😎 Deploy Preview https://deploy-preview-907--phillips-seldon.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

Bumps [vite](https://github.com/vitejs/vite/tree/HEAD/packages/vite) and [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/HEAD/packages/plugin-react). These dependencies needed to be updated together.

Updates `vite` from 7.3.1 to 8.1.5
- [Release notes](https://github.com/vitejs/vite/releases)
- [Changelog](https://github.com/vitejs/vite/blob/main/packages/vite/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite/commits/v8.1.5/packages/vite)

Updates `@vitejs/plugin-react` from 5.1.4 to 5.2.0
- [Release notes](https://github.com/vitejs/vite-plugin-react/releases)
- [Changelog](https://github.com/vitejs/vite-plugin-react/blob/plugin-react@5.2.0/packages/plugin-react/CHANGELOG.md)
- [Commits](https://github.com/vitejs/vite-plugin-react/commits/plugin-react@5.2.0/packages/plugin-react)

---
updated-dependencies:
- dependency-name: "@vitejs/plugin-react"
  dependency-version: 5.2.0
  dependency-type: direct:development
- dependency-name: vite
  dependency-version: 8.1.5
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot
dependabot Bot force-pushed the dependabot/npm_and_yarn/multi-eebdba2d21 branch from ed8e915 to 17719e8 Compare July 27, 2026 18:41
scottdickerson and others added 11 commits July 27, 2026 14:17
Bumps the dev dependency on React from 18.3.1 to 19.2.8 while
preserving the peer-dependency contract that already allowed both
React 18 and React 19 consumers. Also brings along the React
ecosystem packages whose peer types explicitly excluded React 19.

Superseded by attempt #808 (react-dom bumped without react — inconsistent).

## Dependency changes

Dev dependencies bumped:
- react 18.3.1 → 19.2.8
- react-dom 18.2.0 → 19.2.8
- @types/react 18.3.3 → 19.2.17
- @types/react-dom 18.0.11 → 19.2.3
- @testing-library/react 16.0.0 → 16.3.2 (React 19 peer support)
- usehooks-ts 3.1.0 → 3.1.1 (React 19 peer support)
- @chromatic-com/storybook 5.0.1 → 5.2.1 (Storybook 10.6.x peer support)

Added:
- @testing-library/dom ^10.4.1 (peer requirement of @testing-library/react 16.x)

peerDependencies unchanged — still declares
`"react": "^18.3.1 || ^19.0.0"` and `"react-dom": "^18.2.0 || ^19.0.0"`,
so consumers can stay on 18 or move to 19.

## Code changes for React 19 compat

RefObject prop types widened from `RefObject<T>` to `RefObject<T | null>`
(React 19 `useRef<T>(null)` now returns the narrower nullable type):
- CarouselDot.tsx (`scrollableContainerRef`)
- CountryPickerCountryList.tsx (`listRef`)
- FavoritesCollectionTile.tsx (`imageRef`)
- ComboBox.tsx (widened prop + cast for usehooks-ts `useOnClickOutside`)

`useOnClickOutside` cast at call site (usehooks-ts still types as
`RefObject<T>`) — Search.tsx, ComboBox.tsx.

JSX namespace no longer global in React 19; switched to `React.JSX.Element`
or added `import type { JSX }` — utils/index.tsx,
DetailList.stories.tsx, ProgressWizard.stories.tsx.

`React.Children` / `cloneElement` stricter — added explicit generics on
`isValidElement<Props>()` and typed cloneElement calls:
- DetailList.tsx, NavigationSubmenu.tsx, Toast.test.tsx,
  FilterMenu.tsx, ProgressWizard/utils.tsx.

DatePicker.tsx — `useRef()` now requires an initial value; added
`null`/`undefined`. Also removed `extends Record<string, unknown>`
from DatePickerProps (was silently marking every prop `unknown`),
typed forwardRef explicitly, made `locale` optional to match its
`= 'en'` default.

StatefulViewingsList.tsx — removed the same latent
`extends Record<string, unknown>` bug; replaced with
`extends Omit<ViewingsListProps, ...>` so the spread of forwarded
props remains legal.

Search.tsx — added `nodeRef={searchInputRef}` to `<CSSTransition>` so
react-transition-group no longer calls the removed
`ReactDOM.findDOMNode`.

SeldonImage.tsx — switched the workaround `fetchpriority` (lowercase
HTML attr) back to the proper camelCase `fetchPriority` which React
19 now handles natively; removed the accompanying `@ts-expect-error`
and eslint-disable. Also guarded empty `src` with `src || undefined`
to satisfy React 19's stricter empty-string warning.

Button.test.tsx — React 19 hoists `<link>` elements to `<head>`, so
the prefetch-link assertions now query `document.head`.

## Verification

- npm run build → exit 0 (tsc + vite build)
- npm run lint → exit 0 (tsc --noEmit, eslint, stylelint, markdownlint)
- npx vitest run --project=unit → 1042 / 1042 passing

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Storybook 10.2.8's vite peer range (^5||^6||^7) rejected the vite@8
bump. Bumped @storybook/* and eslint-plugin-storybook to ^10.5.5
which widened the peer range to include vite@8.

Pinned typescript, react, react-dom, @types/react, @types/react-dom,
ics, vitest, and glob to match main's lockfile so a fresh install
does not regress on latent typing/runtime issues in DatePicker,
StatefulViewingsList, Search, and calendarLinks.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Two behavior-preserving fixes flagged by code review:

1. SeldonImage — empty src no longer silently skips the error UI.
   Previously `<img src="">` fired the browser onError event which
   set loadingState to 'error' and showed the error icon. With
   `src={src || undefined}` (to silence React 19's empty-src warning)
   the error path never triggered. Now initialize loadingState to
   'error' when !src, and short-circuit the async loadImage so it
   doesn't fire a stray setState after unmount.

2. Search — CSSTransition classes now land on the wrapper div, not
   the inner <input>. React-transition-group's findDOMNode used to
   return Input's outermost DOM node (the wrapper <div>) so
   `.seldon-input-enter` classes were applied there. Switching to
   `nodeRef={searchInputRef}` shifted them to the input element
   itself, a silent DOM-target change for any downstream consumer
   styling those transition classes. Added a dedicated
   searchInputWrapperRef and a wrapping div so nodeRef targets the
   wrapper.

Verified: build passes, lint passes, 1042/1042 unit tests pass, no
unhandled rejections.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…lti-eebdba2d21

# Conflicts:
#	package-lock.json
#	package.json
The prior wrapper-div fix around <CSSTransition> introduced an extra
block that disrupted the flex chain, pushing the input to a new row.
Removes the wrapper and lands the transition classes on the <input>
directly, then updates the SCSS selector from
`.seldon-input-enter-active input` (descendant) to
`.seldon-input__input.seldon-input-enter-active` so the enter-active
background/placeholder styling still applies.

Also:
- Drops stale explanatory comments across Search, SeldonImage, and
  the Button test helper that documented the React-18→19 delta
  rather than the code's current behavior.
- Adds .claude/worktrees to eslint ignores so lint doesn't fail on
  files that belong to a locked git worktree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Prevents `.claude/worktrees/` from being accidentally added as a
submodule entry when the pre-commit hook runs `git add .`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
vite@8 double-wraps CJS default exports in the browser (l10n.default.en),
while node/jsdom still returns the unwrapped shape (l10n.en). Add a
runtime check so both interop patterns resolve to the locale table.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Mirrors the eslint-config change so `npm run coverage` and the
pre-push hook don't pick up test files in a locally-checked-out
worktree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- vite@8's rolldown-based CSS pipeline no longer applies resolve.alias
  to sass @use/@import. Add an explicit sass importer in .storybook so
  ~scss/allPartials keeps resolving.
- vite@8 minifies CSS with lightningcss, which rejects var('...') with
  quoted identifiers. Remove the stray quotes in _composedModal.scss.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@chromatic-com

chromatic-com Bot commented Jul 27, 2026

Copy link
Copy Markdown

Tip

All tests passed and all changes approved!

🟢 UI Tests: 476 tests unchanged
🟢 UI Review: 238 stories published -- no changes
Storybook icon Storybook Publish: 238 stories published

@github-actions

github-actions Bot commented Jul 27, 2026

Copy link
Copy Markdown

@scottdickerson scottdickerson changed the title build(deps-dev): bump vite and @vitejs/plugin-react build(deps-dev): L3-0000 bump vite to 8 and merge React 19 upgrade Jul 27, 2026

Copy link
Copy Markdown
Contributor

🔴 Dependency Upgrade Risk Assessment: HIGH

This assessment was generated automatically by a scheduled dependency review routine.


What is this PR upgrading?

This is a bundled major infrastructure upgrade touching three interconnected parts of the build stack simultaneously:

Package From To Type
vite 7.3.1 8.1.5 Major version
@vitejs/plugin-react 5.1.4 5.2.0 Minor
react / react-dom 18.x 19.x Major version
@types/react / @types/react-dom 18.x 19.x Major
storybook (full family) 10.2.8 10.5.5 Minor

Why does this matter for the broader Phillips ecosystem?

Seldon is the internal Phillips UI component library used by phillips-public-remix (and potentially other Phillips apps). Every component, design token, and primitive exported from seldon is consumed downstream. A regression in seldon's build output or type signatures cascades immediately to all consuming applications.

How widespread is the usage?

Seldon exports are used pervasively throughout phillips-public-remix — every page component, most route-level components, and the majority of UI primitives (Button, Text, Grid, Loader, Toast, tabs, modals, etc.) are sourced from this library. Breaking the seldon build or introducing type incompatibilities would block the entire consumer app from building.

What changed and what workarounds were needed?

The PR body documents several non-trivial compatibility issues that required active fixes:

  1. vite 8 CSS pipeline (rolldown-based) — vite 8 replaced its CSS processing engine with rolldown. The new pipeline stopped applying resolve.alias to @use/@import SCSS directives, breaking ~scss/allPartials resolution. A custom findFileUrl importer had to be added to .storybook/main.ts to restore this.
  2. CSS custom property syntax — lightningcss (vite 8's default CSS minifier) rejects quoted var() values (var('--foo')). Stray quotes in _composedModal.scss had to be stripped.
  3. flatpickr l10n import interop — vite 8's CJS interop changed how flatpickr/dist/l10n/index is resolved between node (jsdom) and browser bundles. A shim was needed in DatePicker.tsx.
  4. React 19 type-level breaking changesRecord<string, unknown> intersections removed, explicit forwardRef generics required, useRef initial-value pattern updated. These are compile-time changes that affect any component using these patterns.

Why HIGH?

  1. Multiple simultaneous major-version upgrades — vite 8 + React 19 together multiply the risk surface; each has its own breaking changes and the combination creates emergent compatibility issues (as the workarounds show).
  2. Seldon is a shared infrastructure library — a regression in its build output affects all downstream consumers, not just this repo.
  3. Build pipeline change — vite 8's rolldown CSS engine processes SCSS differently. Any component using @use/@import patterns that weren't tested could produce broken CSS in production.
  4. React 19 downstream impactphillips-public-remix currently uses React 18. When seldon ships React 19 types, consuming apps may see type errors until they also upgrade.
  5. Workarounds indicate fragility — the number of fixes needed in this PR (3+ distinct compatibility shims) suggests the upgrade surface is broad and other edge cases may remain.

Suggested Regression Tests

Before merging, confirm the following:

Build & Lint

  • npm ci succeeds without --legacy-peer-deps
  • npm run build completes without errors (vite 8 production build)
  • npm run build:storybook produces a valid storybook-static/ directory
  • npm run lint passes cleanly

Unit & Storybook Tests

  • All unit tests pass: npm test -- --run (target: 1042/1042)
  • All Storybook interaction tests pass: npm run test-storybook (target: 238/238)

Key Component Smoke Tests (most likely affected by the workarounds)

  • DatePicker — open the component in Storybook, confirm English weekday shorthand renders correctly (validates the flatpickr l10n interop fix for both dev and production builds)
  • ComposedModal — open in Storybook, confirm the modal body height CSS custom property (--max-modal-body-height) applies correctly (validates the lightningcss var() fix)
  • Any component using forwardRef — verify no TypeScript errors and correct runtime behavior

Chromatic Visual Regression

  • Compare Chromatic snapshots against main — visual diffs should be limited to intentional React 19 surface changes; flag any unexpected layout or style regressions

Downstream Consumer Validation

  • After publishing a preview/canary build of seldon, install it in phillips-public-remix and confirm: npm install, npm run typecheck, and npm run build all pass without requiring React 19 types in the consumer (or document that a consumer upgrade is also required)
  • Verify CSS-heavy components (anything using ~scss/allPartials) render correctly when consumed via the built package (not just in Storybook dev mode)

Generated by Claude Code

vite build exits 0 even when dist/ cannot actually be loaded by an ESM
consumer, so add `npm run smoke` (wired into CI) that loads dist/index.js
and dist/index.cjs the way consumers do and scans for unresolvable runtime
`__require(...)` calls and bundled peer deps.

Externalize @artsy/fresnel: Rolldown cannot hoist its `require('react')`
into a static ESM import when it bundles the package, so the output ships
a runtime `__require('react')` that throws for every ESM consumer.

Also refactor buildUtils tests to use `vi.hoisted` so `glob.sync` is
mockable per-test, and prevent jsdom "Not implemented: navigation" noise
by cancelling default anchor clicks in the shared test setup.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file dependency-upgrade-risk:high javascript Pull requests that update javascript code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants