MUI System v7 到 v9 升级完全指南:废弃 system 属性迁入 sx 与 Grid 方向限制的实战落地
<输出文章结束标记仅为占位,正文见下>
导读
本文以 MUI System v7 升级到 v9 官方迁移文档为骨架,系统梳理本次大版本中最影响日常写码的两类破坏性变更:从 Box、Grid、Stack 等组件上移除废弃的 system 快捷属性(统一收敛到 sx),以及 Grid 不再支持 direction="column"(改由 Stack 承担纵向布局)。读完你会拿到可直接执行的 codemod 迁移命令、逐行的改码对照,以及本仓库 codemod 源码与 Grid 类型定义层面的底层证据,能够安全地把项目从 v7 迁到 v9。
说明:本文聚焦 MUI System(
@mui/system)。如果你的项目同时使用了 Material UI 组件库,其 v9 变更覆盖面更广,可另见 Material UI v7 到 v9 升级指南。
为什么值得升级到 MUI System v9
官方文档在 upgrade-to-v9.md 中给出了两个核心理由,它们共同指向"更少 API 面、更一致行为"的设计方向。
更一致的样式 API:system props 退场,sx 统一收口
v9 从组件上移除了那些已被废弃多年的 system 快捷属性,强制把样式表达收敛到 sx prop 上。收益是三层:
- API 表面积更小:布局类组件不再同时暴露
mt、p、display等几十个透传属性; - 行为更一致:不同组件之间不再存在"有的属性走了样式系统、有的被透传给了 DOM"的分裂;
- 避免属性冲突:这正是文档特别点出的一点——此前像
color这类属性可能被组件"截胡"消费,而不是透传给通过componentprop 渲染的底层元素。
更清晰的布局原语:Grid 管二维,Stack 管纵向
v9 让 Grid 回归"把二维布局切分为列"的本职,不再被用作纵向堆叠容器;纵向布局统一交给 Stack。职责边界越清晰,API 就越容易推理,也越贴合各自的设计意图。这一方向在仓库中同样有明确呈现,见下文 Grid 方向限制。
升级前的整体判断与版本配套
v9 是一次新的主版本(major release),必然伴随公开 API 的破坏性变更。进行升级时请注意:
- 你需要把
@mui/system及其配套依赖提升到9.0.0及兼容版本; - 若同仓使用 Material UI,
@mui/icons-material、@mui/material-nextjs、@mui/styled-engine、@mui/styled-engine-sc、@mui/utils等也需同步到9.0.0(@mui/lab升级到最新的 v9 beta),版本清单见 Material UI v9 升级文档; - 升级前建议先提交干净的基线,逐条应用下文变更并跑一遍类型检查(
tsc)与测试,便于定位回归。
Breaking change 一:废弃的 system 属性被移除
受影响组件
官方文档明确点名了三个组件:Box、Grid、Stack。需要说明的是,文档示例使用的是 @mui/system 下的这几个组件,而仓库中 codemod 的默认组件清单实际覆盖得更广。
查看 codemod 源码 removeSystemProps.js 中的 components 常量,处理对象还包括 Material UI 中继承/复用了 system 能力的 Typography、Link、Grid2、DialogContentText、TimelineContent、TimelineOppositeContent。也就是说:凡是在这些组件上直接写 mt、p、color 等快捷属性的代码,都属于本次清扫范围。
推荐的自动化迁移命令
文档给出的迁移方式是用官方 codemod 一次性改写,命令如下:
npx @mui/codemod@latest v9.0.0/system-props <path/to/folder>
其中 <path/to/folder> 替换为你希望递归处理的源码目录(例如 src/)。codemod 的实现在仓库中的位置是 packages/mui-codemod/src/v9.0.0/system-props/removeSystemProps.js。
手工迁移的代码对照
文档给出了逐组件的最小 diff,务必完整核对:
-<Box mt={2} color="primary.main" />
+<Box sx={{ mt: 2, color: 'primary.main' }} />
-<Grid mt={2} mr={1} />
+<Grid sx={{ mt: 2, mr: 1 }} />
-<Stack mt={2} alignItems="center" />
+<Stack sx={{ mt: 2, alignItems: 'center' }} />
迁移的同时,也顺带修复了文档提到的历史问题:像 color 这样的属性此前可能被组件自身消费掉,而现在它作为 sx 内容被正确应用到 component prop 渲染出的底层元素上。
深入 codemod:它到底改了什么
从源码看,removeSystemProps 的转换策略非常值得理解,因为它决定了你 review diff 时该看什么:
- 属性白名单来自
defaultSxConfig。源码第一行注释写明其属性集合取自 packages/mui-system/src/styleFunctionSx 下的defaultSxConfig.js,涵盖 borders(border、borderRadius、borderColor…)、spacing(p/px/py、m/mx/my及 margin/padding 全拼)、display(display、overflow、whiteSpace…)、flexbox、grid(gap、gridTemplateColumns…)、positions(position、zIndex…)、shadows(boxShadow)、sizing(width、height…)、typography(fontSize、fontWeight…)等全部可被sx消化的键。 - JSX 属性搬移 + 合并。它只把属于白名单、且当前组件受影响的 JSX 属性从元素上剥离并收进新生成的
sx对象;若元素原本已有sx(对象、数组或标识符形式),会按类型智能合并,已有sx永远保留优先级。 - 处理展开属性(spread)。当组件存在
{...restProps}这类展开时,codemod 会追加一个基于restProps.sx的展开合并逻辑(配合Array.isArray判断),尽可能避免丢失运行期传入的样式。 - 特殊组件有例外规则。对
Typography及其派生的DialogContentText、TimelineContent、TimelineOppositeContent,color只有在取inherit、含.(主题色如primary.main)、divider、#hex或函数调用时才搬进sx,其余取值会被保留在组件 prop 上以免误伤文本默认色逻辑;Link类似,但color="inherit"会被保留,因为它在Link上还承担着控制下划线行为的语义。 - 仅处理
@mui开头的导入来源,避免误伤其它库;同时跳过.json与.d.ts文件。
这些行为都有配套测试锁定,见 removeSystemProps.test.js:测试覆盖了标准转换、幂等性(对转换结果再跑一次应保持输出不变)、packageName 选项(支持把 codemod 用于内部封装的 @acme/ui 这类自定义包)以及 jsx 选项(显式声明自动引入、无法通过 import 识别来源的组件名,如 Box,Typography,Stack,Link 或任意自定义名)。
对使用该 codemod 的实践启示:
- 推荐先对目录跑一次,随后用
git diff逐块核对,尤其留意Typography/Link的color是否被正确处理; - 若你的代码把组件从自定义封装里再导出、import 分析识别不到,可通过
--jsx类选项补充组件名(详见 packages/mui-codemod/README.md 对 v9.0.0/system-props 的说明); - codemod 是幂等的,可以在 review 后放心重跑同一目录而不必担心二次污染。
Breaking change 二:Grid 不再支持 direction="column"
变更说明
Grid 组件不再接受 direction="column" 与 direction="column-reverse"。文档给出的理由是:Grid 的定位是把布局切分为列(columns)的二维网格,而不是做纵向堆叠;纵向布局应当使用 Stack。
这一点在源码中有双重印证:
- 类型层面,GridProps.ts 中
GridDirection已被收窄为type GridDirection = 'row' | 'row-reverse'; - 组件注释层面,Grid.tsx 与
GridProps.ts的 JSDoc 均明确写着:只有row和row-reverse被支持,column/column-reverse不受支持,因为Grid是被设计来把布局细分为列而非行的。
Material UI 侧的 v9 文档补充了一个重要背景:这两个取值"在此前版本中实际上就并未被真正支持",本次只是把它们从 TypeScript 类型与 prop 校验中正式剔除。如果你仍需要横向的列细分,请继续使用默认的 direction="row" 或 direction="row-reverse"。
迁移示例:纵向布局改用 Stack
文档给出了完整的前后对照:
-import Grid from '@mui/system/Grid';
+import Stack from '@mui/system/Stack';
-<Grid container direction="column" spacing={2}>
- <Grid>First item</Grid>
- <Grid>Second item</Grid>
-</Grid>
+<Stack spacing={2}>
+ <div>First item</div>
+ <div>Second item</div>
+</Stack>
要点拆解:
Grid container direction="column" spacing={2}整体替换为一个Stack spacing={2}——spacing语义在Stack上原样保留;- 原先每个
Grid子项(即逻辑上的一"行")替换为普通元素(文档用<div>);如果子项内部还需要做水平细分,可以继续在子项内嵌套Grid,即"外层 Stack 负责纵向、内层 Grid 负责横向"的组合(Material UI 侧文档称之为"inside a Grid item when needed"); - 若你是从
@mui/system之外的入口(如@mui/material/Grid)导入,同样适用——纵向堆叠交给Stack(对应入口为@mui/material/Stack)。
一份可对照执行的升级清单
把上述两类变更落到项目里,推荐按如下顺序操作:
-
锁版本:在
package.json中把@mui/system(及配套依赖)提升到 v9 兼容版本,重新安装依赖。 -
跑 codemod 清扫 system 属性:
npx @mui/codemod@latest v9.0.0/system-props src/若还使用了
Typography、Link等派生组件,确认它们也在处理范围内;自定义封装场景参考 README 补充选项。 -
处理 Grid 方向:全局搜索
direction="column"(含column-reverse),逐个按上文 diff 改写为Stack,必要时在Stack子项里保留Grid做水平列细分。 -
检查颜色与透传:重点 review 原先依赖
color等属性被组件"消费"的写法,确认迁移后样式经sx落到了component指定的元素上。 -
验证:运行类型检查与组件测试。由于 codemod 输出可预测且幂等,
git diff应该清晰可审;本仓库的 codemod 测试(幂等、自定义包名、jsx 组件名等用例)可作为你验收改写的参考口径。
参考与进一步阅读
- 本文依据的官方指南:docs/data/system/migration/upgrade-to-v9/upgrade-to-v9.md
- 上一代升级文档(v6 → v7,含早期 deprecated 属性背景):docs/data/system/migration/upgrade-to-v7/upgrade-to-v7.md
- codemod 源码与测试:removeSystemProps.js、removeSystemProps.test.js
- 历史版本(v6.0.0)对应的 system-props codemod:packages/mui-codemod/src/v6.0.0/system-props/removeSystemProps.js,可用于对比两代迁移逻辑差异
- Grid 类型与实现:GridProps.ts、Grid.tsx、createGrid.tsx
- Material UI 组件库侧对应的 v9 升级范围:docs/data/material/migration/upgrade-to-v9/upgrade-to-v9.md
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 StartedRust0625
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00