样式与构建:CSS Modules / Tailwind / Vanilla Extract / Vite / SWC / Turbopack
0. 元信息
- 主题路径:
docs/topics/react-app/subtopics/styling-and-tooling/README.md - 父主题:
react-app - 主分类:前端与客户端
- 辅助分类:工程技术
- 适合对象:想摆脱“脚手架黑盒”、理解构建与样式选型的开发者
- 建议周期:1.5~2 周
- 前置知识:
components-and-jsx、命令行、TypeScript 入门 - 最终目标:能为新项目选样式方案、构建工具与 monorepo 拓扑
1. 学习路线
CSS Modules / Tailwind / Vanilla Extract / shadcn-ui → Vite / esbuild / SWC
→ Next.js / Remix / Astro 框架级构建 → TypeScript / ESLint / Prettier
→ monorepo(pnpm + Turborepo / Nx)→ 性能预算与 RSC 构建限制
2. 阶段周数分配
精简子主题不固定周数。按 §3 顺序完成,每段都能跑通“按需加载的样式 + 增量构建”。
3. 九阶段表
| 阶段 | 核心知识 | 实践产出 | 学会标准 |
|---|---|---|---|
| 1 | CSS Modules、PostCSS、CSS nesting | 多组件 demo | 解释 scoped className |
| 2 | Tailwind:utility-first、theme、plugins、arbitrary values | 卡片 / 列表 | 能配 Tailwind v4 配置 |
| 3 | Vanilla Extract / Linaria:零运行时 CSS-in-TS | design token demo | 解释编译时样式 |
| 4 | shadcn/ui、Radix、Headless UI | 复制粘贴组件库 | 知道“组件即代码”模式 |
| 5 | Vite:esbuild 依赖预构建、HMR、Rollup 产物 | 生产构建报告 | 能读 dist 拆包 |
| 6 | SWC / Turbopack / Rspack | Next.js 15 dev / build | 比较 dev 启动 / HMR |
| 7 | TypeScript:tsconfig strict、JSX 类型、生成 d.ts | 强类型组件库 | 解释 noUncheckedIndexedAccess |
| 8 | ESLint flat config、eslint-plugin-react-hooks、Prettier、lint-staged | 提交钩子 | 提交前自动 fix |
| 9 | pnpm workspaces、Turborepo、changesets | 多包 monorepo | 一次构建所有包、发布版本 |
4. 第一周任务
精简版省略固定日程。优先完成“CSS Modules + Tailwind 并存 + Vite 构建 + ESLint + Prettier”。
5. 阶段通用验收
精简版省略;产物有 build / lint / typecheck / format 四个脚本能跑。
6. 最终验收
精简版省略;以 §3 第 9 阶段和 §9.4 案例口述检查为准。
7. 综合项目
精简版省略;成果并入父主题电商 SPA 的“UI 库 + 工具链 + monorepo 雏形”。
本主题贡献
- 职责 1(样式方案选型与共存):父主题电商 SPA 按 §1 选型原则落地——全局 reset / token 用原生 CSS + CSS Variables,业务组件用 CSS Modules + CSS nesting(§3 阶段 1),营销页与表单用 Tailwind v4 utility(阶段 2),design token 演示用 Vanilla Extract 零运行时(阶段 3);严禁运行时 CSS-in-JS 与 RSC 子树共存(呼应 §9.4 #4)。
- 职责 2(构建链与 RSC 边界):
apps/web用 Vite 5 + esbuild 依赖预构建,apps/web-rsc用 Next.js 15 + Turbopack dev,vite.config.ts显式声明optimizeDeps.include解决“dev 启动慢”(§9.4 #1);Tailwind 动态拼接类名走safelist或完整字符串模板,避免被 purge(§9.4 #3)。 - 职责 3(TypeScript / ESLint / Prettier / monorepo):统一
tsconfig.base.json启用strict+noUncheckedIndexedAccess,ESLint flat config 必含eslint-plugin-react-hooks/eslint-plugin-jsx-a11y;monorepo 用pnpm+ Turborepo + changesets,pnpm install --frozen-lockfile在 CI 强制锁文件;husky + lint-staged提交前自动 fix(§3 阶段 7~9)。 - 交付物 1:
packages/ui提供 Button / Card / Input / Modal / Toast 五个原子组件,每组件一份 CSS Modules 样式 + 一份 Tailwind 等价 demo,README 用对照表说明何时用哪种(呼应“样式方案互斥”原则)。 - 交付物 2:
pnpm-workspace.yaml+turbo.json+package.json#exports完整跑通“ui被web与web-rsc同时依赖、一次构建全部包”;changesets工作流演示pnpm changeset→pnpm version→pnpm publish。 - 交付物 3:
vite.config.ts配build.rollupOptions.output.manualChunks按路由拆包,配合rollup-plugin-visualizer产出dist/stats.html,CI 上传工件。 - 交付物 4:CI 中跑
pnpm lint/pnpm typecheck/pnpm format:check/pnpm build/pnpm test五个脚本,任一红则 PR 阻塞;Node 与 pnpm 版本在.nvmrc+package.json#engines锁定。 - 指标 1:商品详情页(典型 RSC 边界页)首屏 JS payload ≤120 KB(gzipped),Lighthouse Performance ≥90(移动端、节流 4G)。
- 指标 2:HMR 改动
<Button>样式时浏览器刷新时间 ≤300ms(React Fast Refresh + 命名导出),呼应 §3 阶段 5。 - 指标 3:仓库
package.json总依赖数(直接 + 传递去重后)≤800;Tailwind safelist ≤30 条类名;vite build在中端 CI(4 vCPU)≤90s 完成。
8. 推荐资料
精简版省略;使用 §9.3 和 §9.6 Source。
9. 学习资料汇聚(v0.3 自包含)
9.1 背景与动机
样式与构建是“看不见的工程债”高发区。选错样式方案(运行时 CSS-in-JS + SSR 框架)会拖慢首屏;选错构建(Webpack + RSC)会卡 dev server。React 19 + App Router 把“构建能做什么”推到新边界:RSC 要求 bundler 知道 server / client 边界。
样式选型原则:
- 全局 / 静态 → 原生 CSS + PostCSS。
- 组件作用域 + 团队熟悉 → CSS Modules。
- 快速原型 / 一致设计系统 → Tailwind。
- 强类型 / 零运行时 → Vanilla Extract。
- 业务组件库快速搭 → shadcn/ui + Radix。
构建选型:本地起手用 Vite;产品级 + SSR/RSC 用 Next.js;内容站 / 岛屿用 Astro;大规模 monorepo 选 Turborepo / Nx。
9.2 概念地图
flowchart LR
Style[样式方案] --> CSSM[CSS Modules]
Style --> TW[Tailwind]
Style --> VE[Vanilla Extract]
Style --> SCSS[CSS-in-JS 运行时]
Style --> Lib[shadcn/ui / Radix]
Build[构建] --> Vite
Build --> Next[Next.js]
Build --> Remix[Remix]
Build --> Astro
Build --> Rspack
Build --> SWC
Build --> Turbopack
Tooling[工具链] --> TS[TypeScript]
Tooling --> ESLint
Tooling --> Prettier
Tooling --> Husky
Tooling --> Changesets
Monorepo --> pnpm
Monorepo --> Turbo[Turborepo]
Monorepo --> Nx
9.3 基础知识讲解
9.3.1 论文 / 规范
- CSS Working Group:
@scope/ nesting / container queries。 - TC39:Decorator / 标准 CSS-in-JS 提案(未稳)。
- Vite / esbuild 文档:依赖预构建、HMR、产物分析。
9.3.2 书 / 文档
- Refactoring UI(Adam Wathan / Steve Schoger)——Tailwind 背后的设计思路。
- Modern CSS with Tailwind(Noel Rappin)。
- Vite 官方文档。
- Next.js 构建文档。
- Tailwind 文档。
- Vanilla Extract 文档。
9.3.3 博客
- shadcn/ui 博客。
- Addy Osmani:CSS 性能。
- Vercel 博客:构建优化。
- Lee Robinson:Next.js 性能。
- Sébastien Lorber:React 19 + 构建。
- Nx / Turborepo 博客。
9.3.4 人物
- Adam Wathan:Tailwind 创始人。
- Evan You:Vite 创始人。
- Tobias Koppers:Webpack 作者,现维护 Turbopack / Rspack。
- Guillermo Rauch:Next.js / Vercel。
- Dominik Dorfmeister:TanStack 工具链。
- shadcn:组件即代码范式。
9.3.5 方法
- One CSS layer per concern:reset / tokens / components / utilities。
- Tokens via CSS variables + theme provider。
- Co-locate styles with components(CSS Modules / Vanilla Extract)。
- Build budget:
vite build看产物大小,配 CI 失败阈值。 - Lint staged:husky + lint-staged;CI 跑完整 lint。
- Deterministic builds:lockfile、pin Node 版本、pnpm。
- RSC ready:避免构建期副作用(global side effects in module top-level)。
9.4 经典问题与经典案例
| # | 问题 | 为什么重要 | 最简答案或证据 |
|---|---|---|---|
| 1 | dev 启动慢 | 依赖预构建太大 | optimizeDeps.include 显式声明 |
| 2 | HMR 不生效 | 组件默认导出 + 命名导出差异 | 用命名导出 + React Fast Refresh |
| 3 | Tailwind 类不生效 | 动态拼接的类被 purge | 走 safelist / 完整字符串 |
| 4 | CSS-in-JS 在 RSC 报错 | 用了 window / document | 改 CSS Modules / Vanilla Extract |
| 5 | build 产物体积爆炸 | 整包打到一个 chunk | manualChunks / 路由级 lazy |
| 6 | TypeScript 与 ESLint 配置冲突 | tsconfig 严格但 lint 允许 | 用 typescript-eslint 推荐配置 |
| 7 | monorepo 链接失败 | 用了 npm 而非 pnpm | 改 pnpm workspaces |
| 8 | changesets 不发包 | 缺 CI 步骤 | 加 .github/workflows/release.yml |
| 9 | 主题切换闪烁 | SSR 渲染前不知主题 | <html data-theme> 在 server 端决定 |
| 10 | postcss 解析报错 | 用了未注册的语法 | 装 postcss-nesting / 用 Lightning CSS |
9.5 学习难点
- 概念难点:CSS Modules / Tailwind / Vanilla Extract 的“作用域”模型不同。Tailwind 是 utility 工具集,不是组件库。
- 思维难点:构建产物的“运行时边界”——RSC 强制 server / client 拆开,monorepo 强制包边界。
- 工程难点:性能预算、缓存失效、CI 时间、依赖升级。
9.6 技术标准与接口
9.6.1 Entity
| 名称 | 版本 | 组织 | 状态 |
|---|---|---|---|
| Vite | 5+ | Evan You / VoidZero | 活跃 |
| esbuild | 0.20+ | Evan You | 活跃 |
| SWC | 1+ | Vercel | 活跃 |
| Turbopack | 0.x / 稳定中 | Vercel | Next.js 集成 |
| Rspack | 1+ | ByteDance | 活跃 |
| Next.js | 15+ | Vercel | 活跃 |
| Tailwind CSS | 4+ | Tailwind Labs | 活跃 |
| Vanilla Extract | 0.x | Seek / 社区 | 活跃 |
| TypeScript | 5+ | Microsoft | 活跃 |
| ESLint | 9+ flat config | OpenJS Foundation | 活跃 |
| Prettier | 3+ | Prettier team | 活跃 |
| pnpm | 9+ | pnpm team | 活跃 |
| Turborepo | 2+ | Vercel | 活跃 |
9.6.2 Scope
- 样式方案互斥:同一组件用一种为主,避免混用。
- 构建工具互不替代:Vite 不处理 RSC;用 RSC 必须用 Next.js(或 React 19 的 framework bindings)。
- 锁文件:lockfile 必须 commit,CI 装
pnpm install --frozen-lockfile。
9.6.3 Structure
- 必会 Vite 配置:
define/resolve.alias/optimizeDeps/build.rollupOptions。 - 必会 Next.js:
next.config.mjs(experimental.*、turbopack、images、headers)。 - 必会 Tailwind:
tailwind.config.js/@theme/safelist/plugin。 - 必会 monorepo:
pnpm-workspace.yaml/turbo.json/package.json#exports。
9.6.4 Ecosystem
- 组件库:shadcn/ui、Radix、Headless UI、Material UI、Chakra、Mantine、Ant Design、NextUI。
- CSS 工具:PostCSS、Lightning CSS、Stylelint、cssnano。
- 构建分析:
rollup-plugin-visualizer、@next/bundle-analyzer、Lighthouse CI。
9.6.5 Depth Tiers
| 层级 | 可观察能力 |
|---|---|
| L0 | 知道 Vite / Tailwind 存在 |
| L1 | 看得懂配置文件 |
| L2 | 能改 vite / tailwind / next 配置 |
| L3 | 能调通产物体积、HMR、CSS 树摇 |
| L4 | 能写自定义 plugin / 维护 design system |
本计划目标:L3。
9.6.6 Source
- vitejs.dev。
- tailwindcss.com。
- vanilla-extract.style。
- typescript-eslint.io。
- 引用快照:2026-07-30。
10. 常见误区
- 不锁 Node / pnpm 版本
- Tailwind 动态拼接类被 purge
- 运行时 CSS-in-JS 上 RSC
- 一次 import 整包 lodash
- 不用 lockfile
- monorepo 用 npm
- ESLint 不跑 react-hooks 规则
- 没配 build budget
- HMR 不刷新 hooks
- 不读 framework 的官方缓存与构建文档。
11. 所有知识点分类
- 编程语言 2. 数据结构与算法 3. 计算机基础 4. 工程技术 5. Web 与后端 6. 前端与客户端 7. 数据与人工智能 8. 项目与职业能力 9. 安全与可靠性
本计划归属:前端与客户端 主 + 工程技术 辅。