Tailwind在Storybook中不生效的根本原因是构建链路断裂:postcss-loader未插入SCSS处理链导致@apply失效;content路径未覆盖stories文件致响应式类缺失;JIT静态扫描无法解析动态类名如text-${size}-lg。

Tailwind 在 Storybook 里不生效,不是 Tailwind 写错了,而是构建链路断在了三个关键位置:postcss-loader 没插进 SCSS 处理链、content 路径没扫到 stories 文件、动态类名被 JIT 静态扫描直接忽略。
为什么 @apply 在 .scss 文件里完全没反应
Storybook 默认只用 sass-loader 编译 SCSS,跳过了 postcss-loader,导致 @apply 被当作文本原样保留,最终 CSS 里压根没生成对应规则。
- 必须在
.storybook/webpack.config.js的rules中显式插入postcss-loader,顺序严格为:sass-loader→postcss-loader→css-loader -
include必须覆盖组件源码和 Storybook 文件路径,例如:include: [path.resolve(__dirname, '../src'), path.resolve(__dirname, '../storybook')] - 确认
postcss-loader的config.path指向包含postcss.config.cjs的目录(通常是项目根或.storybook)
为什么 md:flex、hover:bg-blue-500 这些类名不生效
Tailwind JIT 是静态扫描,如果 tailwind.config.js 的 content 数组没包含 Storybook 的故事文件路径,这些响应式、伪类规则根本不会生成。
- 检查
content是否包含:"./storybook/**/*.{js,ts,jsx,tsx,vue}"(注意必须以./开头) - 如果用了自定义 stories 目录(如
src/stories),也要加进去:"./src/stories/**/*.{js,ts,jsx,tsx,vue}" - 修改后必须重启 Storybook,热重载不会触发 JIT 重新扫描
为什么 class={`text-${size}-lg`} 渲染出来是空白
JIT 不会执行 JS 模板字符串,它只看到字面量 text-${size}-lg,无法推导出 text-sm-lg 或 text-md-lg 等具体类名。
立即学习“前端免费学习笔记(深入)”;
- 临时验证:把变量展开成固定字符串,比如
class="text-sm-lg text-md-lg",看是否生效 —— 如果生效,就是动态类名问题 - 长期方案:改用
clsx或twMerge,配合白名单预定义,例如:const sizes = ['sm', 'md', 'lg']; sizes.map(s => `text-${s}-lg`) - 避免在 story 文件中直接拼接带插值的 class 字符串;演示变体时优先用 args 控制固定类名组合
如何安全地在 preview.js 中引入 Tailwind 编译后的样式
preview.js 只接受纯 CSS 字节流,不能处理未编译的 SCSS、Sass 变量或 @import url()。它不是构建上下文,只是运行时注入。
- 路径必须从
.storybook/目录出发计算,例如项目结构是src/style/tailwind-output.css,写法是:import '../src/style/tailwind-output.css' - 导入的必须是已编译完成的 CSS,比如通过
tailwindcss -i ./src/input.css -o ./dist/tailwind.css产出的文件 - 如果组件内用了 Sass 变量(如
$primary-color),光靠preview.js导入不够,还得在main.js的webpackFinal中配sass-loader的additionalData注入变量文件
真正容易被忽略的是:JIT 扫描路径漏掉 stories 文件、postcss-loader 插入顺序错位、以及动态类名在 story 层面的“假动态”——它看起来像能跑,其实连构建器都没见过真实值。



















