Material UI + Vite + TypeScript 官方示例深度解析:项目结构、配置项与上手指南
Material UI 官方在仓库中维护了一组与主流构建工具集成的“最小可运行示例”,本篇文章聚焦其中基于 Vite + TypeScript 的示例(examples/material-ui-vite-ts)。它演示了如何用现代 ESM 工程化方式把 @mui/material 及其依赖(含 Emotion 样式引擎)接入一个热更新的开发环境,涵盖脚手架结构、工程化配置、TypeScript 项目引用关系、样式书写方式以及从启动到产出的完整命令链。读完本文,你将掌握一套可直接复制的 Material UI + Vite + TS 工程骨架,并理解每个文件与每个配置项的用途。
一、示例解决什么问题
原文档 examples/material-ui-vite-ts/README.md 对示例的定位是一句话概括:演示如何将 Material UI 与 Vite、TypeScript 组合使用,并内置 @mui/material 及其 peer 依赖,包括 Emotion——Material UI 的默认样式引擎。
在 Material UI 官方文档中,这个示例也是 TypeScript 入门链路里的指定参照物:TypeScript 使用指南 明确说明 Material UI 要求 TypeScript 4.9 及以上,并直接把这个 Vite + TS 示例作为推荐起点。它不是一个“空壳”,而是一个信息完整的可运行 Demo:
- 首页渲染标题、版权行与一个“灯泡”Pro tip 提示;
- 使用
Container / Box / Typography / Link / SvgIcon等核心组件演示布局与排版; - 通过
sx属性演示 Material UI 的样式系统,无需编写单独的 CSS 文件; - 通过
src/App.tsx、src/ProTip.tsx等文件演示“组件拆分 + 自定义图标 + 复用”的组织方式。
也就是说,它同时承担了“Vite 模板示范”“TS 工程化示范”和“MUI 基础用法示范”三重角色。
二、快速启动:安装、开发与构建
示例目录下的文件清单如下:
examples/material-ui-vite-ts/
├── index.html # Vite 的 HTML 入口
├── package.json # 依赖与脚本定义
├── vite.config.ts # Vite 配置
├── tsconfig.json # TypeScript 项目引用(根)
├── tsconfig.app.json # 应用代码编译配置
├── tsconfig.node.json # Vite 配置文件编译配置
├── public/vite.svg
└── src/
├── App.tsx # 根组件
├── ProTip.tsx # 提示条(含自定义 SvgIcon)
├── main.tsx # React 挂载入口
└── vite-env.d.ts # Vite 客户端类型声明
获得示例后,安装依赖并启动开发服务器:
cd examples/material-ui-vite-ts
npm install
npm run dev
dev 命令启动 Vite 开发服务器后,浏览器会自动打开页面,能看到带 Roboto 字体的 Material Design 风格页面。原文档还提供在线体验方式(CodeSandbox 与 StackBlitz 的 “Open in …” 入口),适合不下载代码快速预览。
示例在 package.json 中预置了三类脚本,覆盖“开发—构建—预览”完整链路:
| 命令 | 底层实现 | 作用 |
|---|---|---|
npm run dev |
vite |
启动开发服务器,带 HMR 热更新 |
npm run build |
tsc -b && vite build |
先用 TypeScript 项目引用模式做全量类型检查,再由 Vite 产出生产包 |
npm run preview |
vite preview |
本地预览构建产物,验证生产包效果 |
值得注意 build 脚本的设计:tsc -b(build 模式)会按照 tsconfig.json 中声明的 references 依次检查 tsconfig.app.json 与 tsconfig.node.json 两个子项目,只有类型检查通过后才进入 vite build。这与“先类型安全、再打包”的最佳实践一致。
三、逐文件剖析工程化配置
1. vite.config.ts:极简即正确
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
// https://vite.dev/config/
export default defineConfig({
plugins: [react()],
});
Vite 对 React + TS 场景的开箱即用程度很高,只需要接入官方 React 插件 @vitejs/plugin-react(提供 Fast Refresh 与 JSX 转换支持),无需额外配置路径别名、CSS 预处理或 polyfill。Material UI 的 ESM 产物可被 Vite 原生处理,这也是该示例保持配置极简的原因。
2. index.html:字体与移动端视口
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
<meta name="viewport" content="initial-scale=1, width=device-width" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link
rel="stylesheet"
href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap"
/>
<title>Vite + Material UI + TS</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
几个细节值得关注:
- 采用
initial-scale=1, width=device-width的移动端视口写法,这正是 Material UI 官方建议的移动优先页面配置; - 使用
preconnect提前建立到 Google Fonts 的连接,并加载 Roboto 字重 300/400/500/700,与 Material Design 排版体系和 Material UI 默认主题的字体栈相契合; - 页面不包含任何可见 HTML,只保留
id="root"的挂载点,全部 UI 由 React 渲染; - 脚本以
<script type="module">加载/src/main.tsx,这是 Vite 基于原生 ES Modules 的开发模型。
3. src/main.tsx:React 18+ 的挂载方式
import * as React from 'react';
import * as ReactDOM from 'react-dom/client';
import App from './App.tsx';
ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
);
- 使用
react-dom/client的createRoot并发渲染 API; document.getElementById('root')!通过非空断言告诉 TypeScript 该节点一定存在;- 用
<React.StrictMode>包裹根组件,帮助在开发期暴露副作用问题(如不纯的渲染函数、过期闭包),便于尽早发现隐患; - 注意
import App from './App.tsx'显式携带.tsx扩展名——这是allowImportingTsExtensions开启后的合法写法(见下文 tsconfig),与日常省略扩展名的习惯不同,但同样有效。
4. 三份 tsconfig:项目引用(Project References)的拆分配置
tsconfig.json 本身不做编译,只做“路由”:
{
"files": [],
"references": [
{ "path": "./tsconfig.app.json" },
{ "path": "./tsconfig.node.json" }
]
}
这种拆分是 Vite 官方脚手架(create-vite)的推荐做法:
tsconfig.app.json:负责src/下的应用代码。关键项包括target: ES2020、lib: [ES2020, DOM, DOM.Iterable]、module: ESNext、moduleResolution: bundler、jsx: react-jsx、noEmit: true,并开启strict、noUnusedLocals、noUnusedParameters等严格检查;tsconfig.node.json:负责vite.config.ts等 Node 侧工具链文件,target: ES2022、lib: [ES2023]、同样moduleResolution: bundler且noEmit。
对 Material UI 开发者而言,tsconfig.app.json 中两个配置与体验直接相关:
"moduleResolution": "bundler":面向打包器(Vite/Webpack 等)的解析策略,让 MUI 包内类型声明能被准确解析,并允许按包名直接导入子路径(如@mui/material/Container);"jsx": "react-jsx":自动 JSX runtime,无需在每个文件里import React。
由于两个子项目都设置 noEmit: true,类型检查不会产出任何 .js 文件,真正“产出”代码的是 Vite,二者职责互不干扰。
此外 src/vite-env.d.ts 中仅有一行 /// <reference types="vite/client" />,它为 Vite 特有语法(如 import.meta.env)和静态资源导入提供类型支持。
5. src/App.tsx:布局与样式系统的第一个样例
import * as React from 'react';
import Container from '@mui/material/Container';
import Typography from '@mui/material/Typography';
import Box from '@mui/material/Box';
import Link from '@mui/material/Link';
import ProTip from './ProTip';
function Copyright() {
return (
<Typography
variant="body2"
align="center"
sx={{
color: 'text.secondary',
}}
>
{'Copyright © '}
<Link color="inherit" href="https://example.com/">
Your Website
</Link>{' '}
{new Date().getFullYear()}.
</Typography>
);
}
export default function App() {
return (
<Container maxWidth="sm">
<Box sx={{ my: 4 }}>
<Typography variant="h4" component="h1" sx={{ mb: 2 }}>
Material UI Vite example in TypeScript
</Typography>
<ProTip />
<Copyright />
</Box>
</Container>
);
}
(示例文件中 Link 的 href 为 MUI 官网的占位地址,实际项目替换为自己的站点即可,正文中以通用占位符展示。)
这段代码是理解 Material UI 用法的浓缩样本:
- 导入风格:全部使用
@mui/material/xxx子路径导入。这有利于摇树优化(tree-shaking)与类型解析,是现代推荐写法;依赖中同时包含@mui/icons-material,在需要图标时可按@mui/icons-material/Star类似方式导入; - 布局体系:
Container maxWidth="sm"创建居中的响应式容器,Box sx={{ my: 4 }}提供垂直外边距——my是margin-top+margin-bottom的速记,4对应主题间距的 4 个基准单位(4 × 8px = 32px); - Typography 的 variant 与 component:
variant="h4"决定视觉样式,component="h1"决定渲染出的 DOM 标签(<h1>),语义与视觉解耦,这是 MUI 的典型能力; - sx 简写属性:
mb: 2(margin-bottom)、color: 'text.secondary'(直接引用主题色板语义 token),说明sx是贯穿 MUI 的主题化样式入口; - 模式化组件:
Copyright是一个返回组件的纯函数,body2小号正文 +align="center"+text.secondary弱化色,形成典型的页脚版权样式,并通过new Date().getFullYear()自动更新年份。
6. src/ProTip.tsx:自定义 SvgIcon 的完整示例
import * as React from 'react';
import Link from '@mui/material/Link';
import SvgIcon, { SvgIconProps } from '@mui/material/SvgIcon';
import Typography from '@mui/material/Typography';
function LightBulbIcon(props: SvgIconProps) {
return (
<SvgIcon {...props}>
<path d="M9 21c0 .55.45 1 1 1h4c.55 0 1-.45 1-1v-1H9v1zm3-19C8.14 2 5 5.14 5 9c0 2.38 1.19 4.47 3 5.74V17c0 .55.45 1 1 1h6c.55 0 1-.45 1-1v-2.26c1.81-1.27 3-3.36 3-5.74 0-3.86-3.14-7-7-7zm2.85 11.1l-.85.6V16h-4v-2.3l-.85-.6C7.8 12.16 7 10.63 7 9c0-2.76 2.24-5 5-5s5 2.24 5 5c0 1.63-.8 3.16-2.15 4.1z" />
</SvgIcon>
);
}
export default function ProTip() {
return (
<Typography sx={{ mt: 6, mb: 3, color: 'text.secondary' }}>
<LightBulbIcon sx={{ mr: 1, verticalAlign: 'middle' }} />
{'Pro tip: See more '}
<Link href="https://example.com/">templates</Link>
{' in the Material UI documentation.'}
</Typography>
);
}
(同上,Link 的 href 在原文件指向 MUI 文档中的模板区,正文以占位符展示。)
ProTip 展示了两个进阶用法:
- 自定义图标与
SvgIcon基座:只要把 Material 图标字体的 SVG<path>数据塞进SvgIcon,即可获得尺寸继承、颜色继承等与内置图标完全一致的行为。SvgIconProps保证了类型安全,{...props}透传让调用方可以通过sx={{ mr: 1, verticalAlign: 'middle' }}就地调整间距与对齐; - 通过 sx 完成行内排版:
mt: 6 / mb: 3制造标题与提示之间的节奏,text.secondary弱化提示文字,与Copyright的配色语言保持一致。
可以看到,整个页面没有写一行传统 CSS——布局、间距、颜色全部经由 sx 直连 Material UI 主题设计令牌(design tokens),这正是该示例想传递的“样式即主题”工作方式。
四、依赖清单:每个包的作用
原文档强调示例“包含 @mui/material 及其 peer 依赖”。对照 package.json 可以把依赖分为两组:
运行时依赖:
| 包名 | 角色 |
|---|---|
@mui/material |
Material UI 组件库本体(Button、Container、Typography、SvgIcon、Link、Box 等) |
@mui/icons-material |
基于 Material 图标的 React 图标集合,按需导入 |
@emotion/react |
Emotion 的 React 绑定;Material UI 默认样式引擎的核心运行依赖 |
@emotion/styled |
Emotion 的 styled() API,供 MUI 内部 styled 组件与自定义 styled 使用 |
react / react-dom |
组件运行所需的 React 运行时 |
开发依赖:
| 包名 | 角色 |
|---|---|
vite |
开发服务器与打包器 |
@vitejs/plugin-react |
React Fast Refresh 与 JSX 转换 |
typescript |
类型检查与类型安全 |
@types/react / @types/react-dom |
React 类型声明 |
关于 Emotion 需要特别说明:Material UI 支持多种样式引擎,而 Emotion 是默认引擎。这也是为什么即使示例页面没有显式写 CSS,也必须安装 @emotion/react 与 @emotion/styled——组件内部(包括 sx 属性和样式覆盖机制)依赖它们完成样式注入。官方仓库还提供可替换的 styled-components 适配层(见 packages/mui-styled-engine-sc),默认场景则走 packages/mui-styled-engine。如果要换用 styled-components,仅替换样式引擎是不够的,还需要满足其 peer 依赖要求——这正是本示例把 Emotion 明确定位为“内置依赖”的原因。
另外注意 package.json 声明了 "type": "module",整个示例以 ESM 运行,与 Vite 原生 ESM 模型保持一致。
五、与仓库内其他脚手架示例的关系
该示例不是孤立存在的。Material UI 在 examples 目录下维护了一整套生态集成示例,便于对比不同技术栈的差异:
- 纯 JS 版本 examples/material-ui-vite:与 TS 版几乎同构。有趣的是结构略有差异——JS 版把
Copyright拆成独立文件src/Copyright.jsx,并额外使用一个独立的Copyright组件;TS 版则在App.tsx内部定义Copyright函数。两相对照可以体会 JS/TS 版本在组织习惯上的自由度; - Next.js 版 examples/material-ui-nextjs、examples/material-ui-nextjs-ts:面向 App Router 的 SSR/ISR 场景,包含 Emotion 服务端渲染缓存处理等进阶话题;
- Pages Router 版 examples/material-ui-nextjs-pages-router-ts:面向传统 Next.js pages 路由;
- 此外还有 Vite Tailwind(examples/material-ui-vite-tailwind-ts)、Pigment CSS(examples/material-ui-pigment-css-vite-ts)、Remix、React Router、Gatsby、Preact 等组合。
选择哪一个,取决于目标运行时:
- 纯前端 SPA → 本示例(Vite + TS)是 Vite 场景下的首选起点;
- 需要 SSR/SEO → 选用 Next.js 系列示例;
- 需要与 Tailwind 协同 → 参考 Vite + Tailwind + TS 组合示例。
六、下一步:从此处走向模板与真实业务
原文档在 “What's next?” 中给出的建议是:你已拥有一个可运行示例项目,接下来回到文档浏览 Templates(模板)专区,挑选更接近真实业务形态的起点(如 Dashboard、Sign-in、Blog 等页面级模板),把示例中验证过的“组件 + sx + 主题”工作流迁移过去。
在当前仓库中可以继续深入的配套资料包括:
- TypeScript 使用指南:MUI 对 TS 版本的最低要求与通用实践;
- 组件 API 与示例源码 packages/mui-material/src:本示例用到的
Container、Typography、SvgIcon、Link、Box的实现都集中于此; - 其他官方示例集合 examples:快速横向对比各框架接入方式;
- 自定义样式与主题的进阶说明可参考 packages/mui-material-nextjs 及仓库根目录 README。
七、小结
examples/material-ui-vite-ts 是一个“小而全”的样板工程:用 Vite 提供极速的模块化开发体验,用双 tsconfig 项目引用保证类型检查与打包互不干扰,用 Container/Box/Typography/sx 展示了 Material UI 的主题化样式心智模型,再用 SvgIcon + 组件拆分示范了如何组织可复用 UI 片段。对于希望以“Vite + TypeScript + Material UI”起步的团队或个人开发者而言,把这份示例作为基线再叠加 CssBaseline、主题定制与路由,即可平稳过渡到真实项目开发。
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 StartedRust0624
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