问题背景
在使用 Tailwind CSS v4 构建 monorepo 项目时,遇到了组件库样式优先级和类名生成的问题。
项目结构
xsky-website/ ├── apps/ │ ├── website/ # 主应用 │ ├── admin/ # 管理后台 │ └── storybook/ # 组件文档 └── packages/ └── ui/ # UI 组件库 └── src/ ├── components/ └── styles/ └── global.css
问题一:重复导入 Tailwind CSS
问题描述
最初,
packages/ui/src/styles/global.css 文件包含了:@import 'tailwindcss'; @custom-variant dark (&:where(.dark, .dark *)); /* ... 其他配置 */
而主应用
apps/website/app/app.css 也包含了:@import 'tailwindcss'; @import '@xsky-website/ui/styles/global.css';
这导致 Tailwind CSS 被导入了两次:
- 主应用导入一次
- UI 库的样式文件编译后也包含完整的 Tailwind CSS
问题影响
- 样式优先级问题:后导入的样式会覆盖先导入的样式
- 包体积增大:重复的 Tailwind CSS 代码增加了最终打包体积
- 维护困难:两个地方都在导入 Tailwind CSS,容易造成版本不一致
解决方案
移除组件库中的
@import 'tailwindcss'从
packages/ui/src/styles/global.css 中移除 @import 'tailwindcss',只保留:@custom-variant配置
@theme配置
- CSS 变量定义
@layer base中的自定义样式
@keyframes动画
修改前:
@import 'tailwindcss'; /* ❌ 移除这个 */ @custom-variant dark (&:where(.dark, .dark *)); /* ... */
修改后:
@custom-variant dark (&:where(.dark, .dark *)); /* ... */
原理说明
这是组件库的标准做法:
- 组件库不包含 Tailwind CSS 核心:只提供自定义样式和配置
- 使用者负责导入 Tailwind CSS:主应用导入
@import 'tailwindcss'生成所有工具类
- 避免重复和冲突:确保只有一个地方生成 Tailwind CSS 工具类
问题二:组件库的 Tailwind 类名未被扫描
问题描述
移除
@import 'tailwindcss' 后,发现组件库中的组件使用了大量 Tailwind CSS 类名(如 border-s、bg-gray-300、text-xs 等),但主应用不会自动扫描这些组件代码来生成对应的 CSS 类。问题影响
如果主应用没有扫描组件库的源代码,那么:
- 组件中使用的 Tailwind 类名不会被生成
- 组件样式会失效
- 需要手动在主应用中添加这些类名(不现实)
解决方案
使用
@source 指令扫描组件库代码在 Tailwind CSS v4 中,
@source 指令用于告诉 Tailwind 扫描哪些文件来生成工具类。在主应用的 CSS 文件中添加:
@import 'tailwindcss'; @import '@xsky-website/ui/styles/global.css'; /* 扫描组件库的源代码 */ @source '../../../packages/ui/src/**/*.{js,ts,jsx,tsx}';
修改的文件
apps/website/app/app.css
apps/admin/app/app.css
apps/storybook/.storybook/storybook.css
示例(apps/website/app/app.css):
@import 'tailwindcss'; @plugin '@tailwindcss/typography'; @import '@xsky-website/tailwind-config/share-styles.css'; @import '@xsky-website/ui/styles/global.css'; /* 扫描组件库源代码 */ @source '../../../packages/ui/src/**/*.{js,ts,jsx,tsx}'; /* 扫描第三方库 */ @source '../../../node_modules/@xsky/eris-ui/dist/**/*.{js,ts,jsx,tsx}'; @config '@xsky/eris-ui-preset';
工作原理
1. 主应用导入 Tailwind CSS ↓ 2. @source 指令告诉 Tailwind 扫描指定目录 ↓ 3. Tailwind 分析这些文件,找出所有使用的类名 ↓ 4. 自动生成这些类名的 CSS 样式 ↓ 5. 组件样式正常工作 ✅
最终配置
组件库 (packages/ui/src/styles/global.css)
/* ❌ 不包含 @import 'tailwindcss' */ @custom-variant dark (&:where(.dark, .dark *)); @theme { /* 主题配置 */ } @theme inline { /* 内联主题配置 */ } :root { /* CSS 变量 */ } .dark { /* 暗色主题变量 */ } @layer base { /* 基础样式 */ }
主应用 (apps/website/app/app.css)
/* ✅ 主应用导入 Tailwind CSS */ @import 'tailwindcss'; @plugin '@tailwindcss/typography'; @import '@xsky-website/tailwind-config/share-styles.css'; @import '@xsky-website/ui/styles/global.css'; /* ✅ 扫描组件库源代码 */ @source '../../../packages/ui/src/**/*.{js,ts,jsx,tsx}'; @source '../../../node_modules/@xsky/eris-ui/dist/**/*.{js,ts,jsx,tsx}'; @config '@xsky/eris-ui-preset'; @custom-variant dark (&:is(.dark *)); @theme { /* 主应用的主题配置 */ } /* 其他样式... */
关键知识点
1. Tailwind CSS v4 的 @source 指令
- 作用:告诉 Tailwind 扫描哪些文件来生成工具类
- 语法:
@source '路径/模式';
- 支持通配符:可以使用
*/*.{js,ts,jsx,tsx}等模式
- 多个
@source:可以添加多个@source指令扫描不同目录
2. 组件库的最佳实践
- ✅ 不包含
@import 'tailwindcss'
- ✅ 只提供自定义样式和配置
- ✅ 要求使用者导入 Tailwind CSS
- ✅ 使用
@source让使用者扫描组件库代码
3. CSS @import 规则的位置要求
@import规则必须在所有其他规则之前(除了@charset或空的@layer)
@import 'tailwindcss'应该放在文件最顶部
- 其他
@import语句也应该在顶部,但可以在@import 'tailwindcss'之后
4. 样式优先级
- 后导入的样式会覆盖先导入的样式
- 因此要确保 Tailwind CSS 工具类在主应用生成
- 组件库的样式文件只包含自定义样式,不会覆盖工具类
常见问题
Q: 为什么组件库不直接包含 Tailwind CSS?
A: 避免重复导入和版本冲突。如果组件库包含 Tailwind CSS,而主应用也包含,会导致:
- 样式重复
- 包体积增大
- 可能的版本冲突
Q: 如果组件库被其他项目使用怎么办?
A: 使用文档中需要说明:
/* 在使用组件库的项目中 */ @import 'tailwindcss'; @import '@xsky-website/ui/styles/global.css'; /* 扫描组件库源代码 */ @source 'node_modules/@xsky-website/ui/src/**/*.{js,ts,jsx,tsx}';
Q: @source 路径如何确定?
A: 路径是相对于 CSS 文件的位置:
- 从
apps/website/app/app.css到packages/ui/src:../../../packages/ui/src
- 使用通配符匹配所有相关文件:
*/*.{js,ts,jsx,tsx}
总结
- 组件库不包含 Tailwind CSS 核心:只提供自定义样式和配置
- 主应用负责导入 Tailwind CSS:生成所有工具类
- 使用
@source扫描组件库:确保组件中使用的类名被生成
- 遵循 CSS 规范:
@import规则必须在顶部
- 避免重复导入:确保只有一个地方生成 Tailwind CSS 工具类
这样的配置既保证了样式正常工作,又避免了重复和冲突,是组件库开发的最佳实践。