Skip to content

Upgrade to MUI v6, MUI X v7, styled-components v6, and Vite 8 - #607

Draft
somethingnew2-0 wants to merge 1 commit into
pcollins/remove-react-hook-form-muifrom
pcollins/mui-v6-vite-8
Draft

Upgrade to MUI v6, MUI X v7, styled-components v6, and Vite 8#607
somethingnew2-0 wants to merge 1 commit into
pcollins/remove-react-hook-form-muifrom
pcollins/mui-v6-vite-8

Conversation

@somethingnew2-0

Copy link
Copy Markdown
Collaborator

Stacked on #606. Review that one first; this PR targets its branch, so retarget to main once it merges.

Supersedes #490, which cannot work on its own.

Why #490 fails today

Vite 8 replaced the dependency optimizer's CommonJS interop and no longer unwraps a Babel-style __esModule default export. @mui/icons-material v5 ships CJS at the top level with no exports map, so every @mui/icons-material/X deep import resolves to {default: Icon} rather than the component, and React refuses to render it. That is the Element type is invalid ... but got: object flood: 109 icon imports across 40 files.

Two things made it worse than it looked. It affects the production build identically, not just dev, so it is not a dev-server quirk. And vite build still exits zero, so CI stays green while the app is unusable.

@mui/icons-material v6 adds an exports map routing the import condition to its ESM build, so the interop step disappears rather than being worked around. That is the actual fix, and it is why the version bump has to come with it.

Why these packages move together

Each pins the others through peer ranges, so a partial bump just produces ERESOLVE:

  • MUI X v6 peers @mui/material ^5.4.1, so MUI v6 requires X v7.
  • @mui/styled-engine-sc v6 peers styled-components ^6.0.0.
  • @mui/lab for the v6 line is still a prerelease, consistent with the v5 alpha it replaces.

Call-site changes

Only three things needed touching, all narrow:

  • renderOption now supplies its own key, so the explicit key={id} has to come after the spread to keep winning. Three search fields.
  • UseDateFieldProps and BaseSingleInputFieldProps each take an extra type argument for the field DOM structure. Passing false selects the structure the picker still defaults to and that ButtonField reads InputProps/inputProps from, so this is a type-level change with no runtime effect.
  • The @rollup/rollup-* platform pins are dropped. Vite 8 bundles with rolldown, rollup is no longer in the tree, and the lockfile already carries all 15 @rolldown/binding-* platforms, so the cross-platform install the pins existed to protect is covered without them.

Also fixes two warnings Vite 8 raises about its future native config loader: the extensionless config import, and __dirname inside an ESM module, which only worked because the config is bundled to CJS first.

Verification and one gap

The bundle grows about 10 kB gzipped, expected for the major. Worth noting it is not a duplicated styling engine: there is a single MUI copy and emotion is not bundled, with the styled-components engine still generating the classes. Lazy code splitting still emits its own chunk.

A browser pass covered the app shell and every previously broken icon, the forms, and the date range picker with its custom field and day-highlight slots.

Not runtime-verified: the MUI X DataGrid. Local seed data has no expiring access and no role members, and both entry points render empty states instead of a grid, so the four DataGrid call sites are typecheck-only here and want a look with real data.

Separately, the ending-date-range picker mishandles the second click of a range, keeping the previous start date. That reproduces identically on main, so it is pre-existing and left alone rather than folded in here.

🤖 Generated with Claude Code

Vite 8 replaced the dependency optimizer's CJS interop, and it no longer unwraps
a Babel-style `__esModule` default export. @mui/icons-material v5 ships CJS at
the top level with no `exports` map, so every `@mui/icons-material/X` deep import
resolved to `{default: Icon}` instead of the component and React refused to render
it. This affected dev and production builds alike, while `vite build` still
succeeded, so CI stayed green.

@mui/icons-material v6 adds an `exports` map routing the `import` condition to its
ESM build, so the interop step disappears rather than being worked around. Getting
there requires moving MUI, the styled-components engine, and MUI X together,
because each pins the others through peer ranges.

Three call-site changes fall out of the majors: `renderOption` now supplies its own
`key`, so the explicit one has to come after the spread to keep winning;
`UseDateFieldProps` and `BaseSingleInputFieldProps` each take an extra type argument
for the field DOM structure, which the picker still defaults to the value ButtonField
expects; and the stale `@rollup/rollup-*` platform pins are dropped, since Vite 8
bundles with rolldown and the lockfile already carries all 15 rolldown bindings.

Also addresses two warnings Vite 8 raises about its future native config loader:
the extensionless config import, and `__dirname` in an ESM module that only worked
because the config was bundled to CJS first.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant