Material UI v4 到 v5 迁移实战:ThemeProvider 前置准备、包名重构与 preset-safe codemod 全流程
本文基于 Material UI 仓库官方迁移文档 migration-v4.md,完整覆盖从 v4 升级到 v5 的每一步前置准备:浏览器与 Node 目标版本变化、React/TypeScript 最低版本要求、ThemeProvider 强制前置、@material-ui/* 到 @mui/* 的包名重构,以及 preset-safe、variant-prop、link-underline-hover 三个 codemod 的适用条件与限制。读完并照做后,你可以按“小步提交、逐步验证”的节奏把应用平稳升到 v5,并能用仓库内 codemod 源码验证每一类转换的底层行为。
迁移系列文档导航
这是一篇多部分系列文档的第一篇,完整迁移路线如下:
- 开始迁移(本文)
- 破坏性变更(一):样式与主题
- 破坏性变更(二):组件
- 从 JSS 迁移
- 故障排查
官方强烈建议优先运行仓库提供的 codemods,它们能自动处理 v5 引入的大部分破坏性变更,本文“运行 codemods”一节详细说明。
为什么应该迁移到 v5
v5 相对 v4 包含大量 bug 修复与改进,其中最重要的变化是样式引擎从 JSS 换成了 Emotion:
- 动态样式的性能有显著提升,开发体验更好;
- v5 是唯一完整支持 React 18 的版本,想用 React 18 的新特性就必须迁移;
- v5 发布详情可参考仓库内的发布博客 mui-core-v5.md。
两个关键的过渡性事实:
- JSS 可以继续用:迁移到 v5 后,你仍可继续使用
makeStyles、withStyles等 JSS 工具给组件添加覆盖样式(通过已废弃但仍可用的@mui/styles包)。官方建议是:先完成其余 v5 升级步骤,再按 从 JSS 迁移 渐进式切换到新样式引擎。 - 小步提交:迁移过程中每完成一步就提交一次,出问题先查 故障排查 文档。
支持的浏览器与 Node 版本
v5 调整了默认构建产物(default bundle)的目标版本,由 browserslist 查询语句锁定:
"> 0.5%, last 2 versions, Firefox ESR, not dead, not IE 11, maintained node versions"
v5.0.0 发布时快照的最小支持版本(相对 v4 的变化):
| 运行环境 | v5 最低版本 | v4 最低版本 |
|---|---|---|
| Node | 12 | 8 |
| Chrome | 90 | 49 |
| Edge | 91 | 14 |
| Firefox | 78 | 52 |
| Safari | 14 (macOS) / 12.5 (iOS) | 10 |
Material UI v5 不再支持 IE 11。如果必须支持 IE 11,官方提供了 legacy bundle 构建方式作为替代方案(见仓库内“minimizing bundle size”指南)。
仓库内的 .browserslistrc 佐证
仓库根目录的 .browserslistrc 就是这份目标声明的落地文件:[stable] 段是随主版本发布时固定的浏览器清单快照,[node]/[coverage]/[development]/[test] 段则分别固定 Node 版本(当前快照为 node 14.0)。从当前文件内容看,stable 快照已演进到 Chrome/Edge 117+、Firefox 121+、Safari 17+,说明该目标基线随版本持续抬高——上面表格是 v5.0.0 发布时的快照,你升级时应以你所发布版本对应的 .browserslistrc 为准。文件头部注释也明确说明:更新版本后可能需要同步仓库中所有标注 #stable-snapshot 的引用(本文原文中的版本表格即由该标记驱动生成)。
更新 React 与 TypeScript 版本
更新 React
React 最低支持版本从 16.8.0 提升到 17.0.0。如果你的 React 低于 17,先把依赖升到 Material UI ^4.11.2 + React ^17.0.0:
npm install @material-ui/core@^4.11.2 react@^17.0.0
yarn upgrade @material-ui/core@^4.11.2 react@^17.0.0
更新 TypeScript
TypeScript 最低支持版本从 3.2 提升到 3.5。官方与 DefinitelyTyped(npm 上 @types 命名空间的类型包)发布的类型对齐,且承诺不会在 minor 版本中提高最低支持版本;一般建议不要使用低于 DefinitelyTyped 最低支持版本的 TypeScript。
如果项目中存在以下包,需要一并更新:
react-scripts@types/react@types/react-dom
检查点:确认应用无错误运行后提交代码,再进入下一步。
设置 ThemeProvider(强制前置条件)
在升级到 v5 之前,无论是否使用默认主题,都必须确保 ThemeProvider 已定义在应用根部和测试中,并且 useStyles 的调用位置晚于/位于 ThemeProvider 内部。这个要求对后续 JSS 过渡期同样有效——@mui/styles 包依赖 ThemeProvider 提供主题上下文。
应用根部结构示例(直接继承自官方文档):
import { ThemeProvider, createMuiTheme, makeStyles } from '@material-ui/core/styles';
const theme = createMuiTheme();
const useStyles = makeStyles((theme) => {
root: {
// some CSS that accesses the theme
}
});
function App() {
const classes = useStyles(); // ❌ If you have this, consider moving it
// inside of a component wrapped with <ThemeProvider />
return <ThemeProvider theme={theme}>{children}</ThemeProvider>;
}
检查点:确认应用无错误运行并提交后,再进入下一步。
更新 Material UI 相关包
安装 v5 主包与过渡包
npm install @mui/material @mui/styles
yarn add @mui/material @mui/styles
若你使用了 @material-ui/lab 或 @material-ui/icons,需要安装对应新包:
npm install @mui/lab
npm install @mui/icons-material
yarn add @mui/lab @mui/icons-material
日期时间选择器已迁往 MUI X
@material-ui/date-pickers 以及 @mui/lab 中的 pickers 组件已移入 MUI X 产品线,如在使用需迁移到 @mui/x-date-pickers(该仓库内的迁移文档为 pickers-migration.md)。
Emotion 依赖
v5 默认样式引擎是 Emotion,需补充 peer 依赖:
npm install @emotion/react @emotion/styled
yarn add @emotion/react @emotion/styled
styled-components 替代方案(可选):若希望用 styled-components 而非 Emotion,可改用适配包 @mui/styled-engine-sc。注意:若应用使用 SSR,styled-components 的 Babel 插件存在已知 bug(官方 issue #29742),会导致 @mui/styled-engine-sc 无法正常工作——官方强烈建议直接用默认 Emotion 方案。仓库中两套引擎适配层的源码分别位于 mui-styled-engine(Emotion)与 mui-styled-engine-sc(styled-components),可以对照其实现理解适配边界。
检查点:确认应用无错误运行并提交后,再进入下一步。
替换所有 import:包名映射总表
v5 随品牌重塑将所有 @material-ui/* 包改名为 @mui/*,映射关系如下:
@material-ui/core -> @mui/material
@material-ui/unstyled -> @mui/base
@material-ui/icons -> @mui/icons-material
@material-ui/styles -> @mui/styles
@material-ui/system -> @mui/system
@material-ui/lab -> @mui/lab
@material-ui/types -> @mui/types
@material-ui/styled-engine -> @mui/styled-engine
@material-ui/styled-engine-sc -> @mui/styled-engine-sc
@material-ui/private-theming -> @mui/private-theming
@material-ui/codemod -> @mui/codemod
@material-ui/docs -> @mui/internal-core-docs
@material-ui/envinfo -> @mui/envinfo
这份映射在本仓库的 monorepo 目录结构中可以得到印证:packages/ 下已按新品牌组织,如 mui-material、mui-lab、mui-icons-material、mui-system、mui-types、mui-utils、mui-private-theming、mui-envinfo、mui-codemod,文档包则对应 core-docs。
移除旧包
安装完所有新包且确认应用正常运行后,可以移除旧的 @material-ui/* 包:
npm uninstall @material-ui/*
# 或
yarn remove @material-ui/*
preset-safe codemod(下一节)会自动完成 import 替换与包名切换,通常无需手动执行。
修正 CSS 特异性(可选)
如果你通过导入 CSS 文件的方式给组件加样式,v5 中需要提高选择器特异性才能命中目标部件。示例(继承自官方文档):
import './style.css';
import Chip from '@mui/material/Chip';
const ChipWithGreenIcon = () => (
<Chip
classes={{ deleteIcon: 'green' }}
label="delete icon is green"
onDelete={() => {}}
/>
);
正确的做法是借助组件根的 MuiChip-root 类提升特异性:
.MuiChip-root .green {
color: green;
}
而下面的写法不会把样式应用到删除图标上:
.green {
color: green;
}
原因在于:Emotion 生成的类(如 MuiChip-root)与 classes 传入的类名挂在同一 DOM 层级的父子关系上,单类选择器 .green 的特异性与组件内置样式打平时可能被覆盖,加上 .MuiChip-root 前缀后形成后代组合选择器,才能稳定胜出。
运行 codemods
以下 codemod 会自动完成大部分 v5 破坏性变更的代码调整。每运行完一个 codemod,都要确认应用仍能无错误运行并提交代码。
preset-safe(主力迁移工具)
包含迁移所需的大多数转换器,每个文件夹只应运行一次:
npx @mui/codemod@latest v5.0.0/preset-safe <path>
从源码看,preset-safe.js 是一个顺序执行约 50 个 jscodeshift 转换器的组合函数,覆盖主题迁移(theme-spacing、theme-breakpoints、theme-augment、create-theme)、组件 prop 变更(icon-button-size、dialog-props、modal-props、table-props)、样式迁移(material-ui-styles、emotion-prepend-cache、styled-engine-provider)、包名替换(mui-replace)与最优导入路径(optimal-imports)等类别,官方 README 中给出了每个子转换器的独立运行命令与 diff 示例,行为则由 preset-safe.test.js 等测试用例固化。
codemod CLI 本身还提供更细的控制选项(来自 mui-codemod README):
npx @mui/codemod@latest <codemod> <paths...>
# 常用选项:
# --dry 干跑,不修改任何文件
# --parser jscodeshift 解析器(默认 'tsx',可选 flow 等)
# --print 把转换结果打印到 stdout
# --packageName 使用了自定义再导出包名时指定,例如 --packageName="@org/ui"
# --jscodeshift 透传 jscodeshift 参数,如 "--run-in-band --verbose=2"
建议先加 --dry 预览改动范围,再正式执行。
variant-prop(TextField / FormControl / Select 变体)
该 codemod 为未定义 variant 的 <TextField/>、<FormControl/>、<Select/> 补上 variant="standard"——因为默认 variant 从 v4 的 "standard" 变成了 v5 的 "outlined"。
禁止使用的场景:如果你已在主题中把默认 variant 设为 outlined,就不要运行它,否则会造成重复/冲突:
// ❌ 如果你有这样的主题配置,不要运行此 codemod
// 这些 defaultProps 后续可以移除,因为 v5 中 outlined 已是默认值
createMuiTheme({
components: {
MuiTextField: {
defaultProps: {
variant: 'outlined',
},
},
},
});
若你确实希望保留 variant="standard",则运行该 codemod 或在主题中配置对应 defaultProps:
npx @mui/codemod@latest v5.0.0/variant-prop <path>
link-underline-hover(Link 下划线)
该 codemod 为未定义 underline 的 <Link /> 补上 underline="hover"——默认值从 v4 的 "hover" 变成了 v5 的 "always"。
禁止使用的场景:若主题中已默认 underline: "always",不要运行:
// ❌ 如果你有这样的主题配置,不要运行此 codemod
// 该 defaultProps 后续可移除,因为 v5 中 always 已是默认值
createMuiTheme({
components: {
MuiLink: {
defaultProps: {
underline: 'always',
},
},
},
});
若希望保留 underline="hover",运行该 codemod 或配置对应主题 defaultProps:
npx @mui/codemod@latest v5.0.0/link-underline-hover <path>
处理剩余破坏性变更
codemods 覆盖了大部分变更,但仍有一类需要手工处理。无论是否使用了 codemods,接下来都应按顺序阅读并完成两篇破坏性变更文档:
完成后按 从 JSS 迁移 切换样式引擎;遇到异常时优先查阅 故障排查。
另外,如果你使用 Next.js 且不确定如何配置 SSR 让 Emotion 与 JSS 共存,本仓库内置了可直接参考的迁移示例工程 examples/material-ui-nextjs-ts-v4-v5-migration/,其中 src 与 types 目录展示了双引擎共存下的服务端渲染配置方式,可作为升级过程中的对照模板。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00