Tailwind CSS v4 + monorepo 配置踩坑笔记

Tailwind CSS v4 + monorepo 配置踩坑笔记

更新时间
Last updated November 19, 2025
AI 占比
Tags
前端
架构
tailwind
description

问题背景

在使用 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 被导入了两次:
  1. 主应用导入一次
  1. 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-sbg-gray-300text-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}';

修改的文件

  1. apps/website/app/app.css
  1. apps/admin/app/app.css
  1. 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.csspackages/ui/src../../../packages/ui/src
  • 使用通配符匹配所有相关文件:*/*.{js,ts,jsx,tsx}

总结

  1. 组件库不包含 Tailwind CSS 核心:只提供自定义样式和配置
  1. 主应用负责导入 Tailwind CSS:生成所有工具类
  1. 使用 @source 扫描组件库:确保组件中使用的类名被生成
  1. 遵循 CSS 规范@import 规则必须在顶部
  1. 避免重复导入:确保只有一个地方生成 Tailwind CSS 工具类
这样的配置既保证了样式正常工作,又避免了重复和冲突,是组件库开发的最佳实践。