自学教程

Tailwind CSS V4 源文件类名检测

Tailwind CSS V4 源文件类名检测完全指南(@source指令)

在 Tailwind CSS V3 时代,我们需要在 tailwind.config.js 的 content 数组手动配置扫描文件路径,告诉Tailwind去哪里找工具类。

Tailwind CSS V4 实现自动源文件扫描,不再需要配置content数组。底层会把源文件当做纯文本扫描,提取能够匹配工具类特征的字符串,只生成代码中实际用到的CSS,实现CSS体积最小化。同时新增CSS顶层指令 @source,用来接管扫描规则:增加扫描目录、忽略目录、强制生成类名、排除类名。

本文基于官方文档,讲解扫描原理、动态类名踩坑、@source全套语法、Monorepo场景、白名单/黑名单,配套可运行示例与避坑清单。

一、类名检测底层原理

Tailwind不会真正解析JSX/Vue模板、不会执行JS代码,它仅仅把所有源文件当做纯文本,使用正则匹配,提取看起来像工具类的文本片段。

关键点:它看不到运行时拼接出来的类名,只能看到源码里写死的完整字面字符串。

自动扫描的文件与自动忽略规则

V4自动扫描项目源码,但是会默认跳过下面这些文件/目录,无需手动配置:

  • 在 .gitignore 里面的全部文件与目录
  • node_modules 依赖目录
  • 二进制文件:图片、视频、压缩包等
  • CSS样式文件、lock锁文件

二、动态拼接类名大坑(高频踩坑)

因为Tailwind是编译期静态文本扫描,不执行JS,如果你用变量拼接生成部分类名,源码中不存在完整类名字符串,Tailwind不会生成对应的CSS,页面样式失效。

❌错误写法:拼接片段

HTML模板示例

<!-- 不要使用插值拼接类名片段 -->
<div class="text-{{ isError ? 'red' : 'green' }}-600"></div>

React JSX示例

// 禁止:使用变量拼接类名片段
function Button({color}){
  return <button className={`bg-${color}-500`}>按钮</button>
}

✅正确写法:完整字面字符串,使用映射对象

HTML模板

<div class="{{ isError ? 'text-red-600' : 'text-green-600' }}"></div>

React JSX,映射表方案(官方推荐)

function Button({color,children}){
  const variantMap = {
    blue:"bg-blue-600 hover:bg-blue-500 text-white",
    red:"bg-red-600 hover:bg-red-500 text-white",
    green:"bg-green-600 hover:bg-green-500 text-white"
  }
  return <button className={variantMap[color]}>{children}</button>
}

原理:所有工具类完整字符串写在源码对象字面量中,Tailwind扫描文本可以识别全部类名,编译时生成CSS。

只有万不得已的时候,才使用 @source inline() 强制生成类名,优先使用映射对象。

三、@source指令完整语法

V4全部在CSS中使用@source指令,替代V3 config中的content、safelist等配置,支持:添加扫描路径、忽略路径、设置扫描根目录、关闭自动扫描、强制生成类名、排除类名。

1. 添加额外扫描路径

场景:需要扫描被默认忽略的目录,例如npm内部组件库。路径相对于当前CSS文件。

@import "tailwindcss";
/* 扫描node_modules内的内部UI组件库 */
@source "../node_modules/@company/ui-lib";

2. 设置扫描基准目录 source(“路径”)

适用于Monorepo仓库,构建脚本运行在仓库根目录,而不是子项目目录,手动指定扫描根目录。

@import "tailwindcss" source("../src");

3. 忽略指定路径 @source not

某些目录不需要扫描,例如遗留旧业务代码,减少扫描耗时。

@import "tailwindcss";
@source not "../src/components/legacy";

4. 完全关闭自动扫描 source(none)

关闭全部自动扫描,所有扫描路径全部手动通过@source声明。适合多份tailwind样式文件,每份样式只生成自己需要的类名,互相隔离。

@import "tailwindcss" source(none);
@source "../admin";
@source "../shared";

5. 强制生成类名 @source inline()(白名单,替代V3 safelist)

源码文本中找不到完整类名字符串,但运行时会使用,强制编译输出对应的CSS。这属于兜底手段,尽量少用。

生成单个工具类

@import "tailwindcss";
@source inline("underline");

同时生成变体 hover / focus

@import "tailwindcss";
@source inline("{hover:,focus:,}underline");

大括号展开语法,批量生成色阶工具

/* 生成bg-red-50 ~ bg-red-950,同时带hover变体 */
@source inline("{hover:,}bg-red-{50,{100..900..100},950}");

6. 排除类名 @source not inline()(黑名单)

即使源码扫描到了该类名,也强制不输出对应的CSS,用于精简CSS体积,剔除不需要的色系。

@import "tailwindcss";
@source not inline("{hover:,focus:,}bg-red-{50,{100..900..100},950}");

四、@source使用场景总结

业务场景V4方案
普通业务项目什么都不用写,V4自动扫描
扫描npm包里的组件库@source "../node_modules/xxx"
Monorepo多包项目,扫描目录错位@import "tailwindcss" source("../src")
忽略旧代码目录,提升编译速度@source not "path"
多套独立Tailwind样式,互相隔离source(none) + 手动@source
运行时动态类名,源码无完整字符串(兜底)@source inline()
强制剔除部分不需要工具类,缩减CSS@source not inline()

五、V3 迁移对比

功能Tailwind V3Tailwind V4
扫描文件路径配置tailwind.config.js content数组默认自动扫描;使用@source补充/调整
白名单强制生成类名config中 safelistCSS @source inline()
黑名单排除类名无原生配置,需要purgeCSS额外处理CSS @source not inline()
关闭全部自动扫描不支持source(none)
配置文件位置JS配置文件全部写在CSS源码内

六、高频避坑清单

  • ❌ 不要做字符串片段拼接类名,编译期只能识别源码完整字面字符串;优先用对象映射表。
  • ⚠️ @source inline()属于兜底手段,不要滥用,大量使用会让CSS体积膨胀。
  • ⚠️ @source的路径是相对于当前CSS文件,不是项目根目录,路径写错不会扫描到文件。
  • ⚠️ CDN浏览器版本 @tailwindcss/browser@4 不会执行文件扫描逻辑,全部工具类都会生成,@source相关指令在CDN环境无效果;@source仅在Vite / PostCSS / CLI构建NPM工程生效。
  • ✅ Monorepo项目优先使用 source("../src") 指定基准路径,解决扫描目录错位问题。
  • ✅ node_modules会被默认忽略,扫描内部UI库需要手动加@source。

总结

Tailwind CSS V4最大的变化就是取消强制的content配置,自动扫描源文件。底层只是文本扫描,无法识别运行时JS拼接的类名。

日常开发优先保证源码写完整工具类字面量;遇到特殊场景使用CSS顶层指令 @source:追加扫描路径、忽略路径、兜底强制生成类名、排除类名。

记住:@source inline()是兜底,不要当做常规手段。动态样式优先用对象映射表解决。

标签:

0 条笔记