Vitest css 配置完全指南:CSS 处理、CSS Modules 与类名作用域策略

Vitest css 配置完全指南:CSS 处理、CSS Modules 与类名作用域策略 Vitest css 配置完全指南CSS 处理、CSS Modules 与类名作用域策略【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitestVitest 的css配置项决定了测试运行期间 CSS 文件如何处理是走完整的 Vite 管线解析还是被替换为空字符串以跳过处理以及 CSS Modules 的类名如何生成。本指南围绕 docs/config/css.md 展开结合 cssEnabler.ts 与 css-modules.ts 的源码实现帮助你在快照测试、组件测试等场景下精准控制 CSS 行为。概览css配置项// vitest.config.ts export default defineConfig({ test: { css: true, // 或者使用对象形式 }, })类型boolean | { include?, exclude?, modules? }默认值见下文的css.include与css.modules默认值说明配置是否处理 CSS。当 CSS 被排除excluded时CSS 文件会被替换为空字符串从而跳过后续处理CSS Modules 则会返回一个 Proxy以免影响运行时行为。::: warning 该选项不适用于浏览器模式测试browser tests。从源码看config.ts 中generateScopedName的注入逻辑带有!browserEnabled条件且浏览器测试由真实浏览器执行 CSS因此本配置对浏览器模式无效。 :::布尔值与对象形式从 cssEnabler.ts 的shouldProcessCSS实现可以看到判定逻辑const shouldProcessCSS (id: string) { const { css } viteConfig.test if (typeof css boolean) { return css } if (toArray(css.exclude).some(re re.test(id))) { return false } if (toArray(css.include).some(re re.test(id))) { return true } return false }配置为boolean时true表示处理所有 CSSfalse表示全部跳过配置为对象时先看exclude是否命中命中即不处理再看include是否命中命中即处理两者都不命中则不处理。此外cssEnabler.ts 中定义了文件识别规则支持的语言包括css、less、sass、scss、styl、stylus、pcss、postcssconst cssLangs \\.(?:css|less|sass|scss|styl|stylus|pcss|postcss)(?:$|\\?) const cssModuleRE new RegExp(\\.module${cssLangs}) const cssInlineRE /[?]inline(?:|$)/css.include指定哪些 CSS 走 Vite 管线类型RegExp | RegExp[]默认值[]include用于匹配「应该返回真实 CSS 内容、并由 Vite 管线处理」的文件。当你不希望所有 CSS 都被处理、只希望部分样式生效时用它精确圈定范围。::: tip 要处理所有CSS 文件可以使用/./。 :::// vitest.config.ts export default defineConfig({ test: { css: { include: [/\.module\.css$/, /base\.css$/], }, }, })处理后的真实 CSS 会通过 Vite 的样式更新机制注入运行时——见 moduleEvaluator.ts 中的updateStyle函数它负责将 CSS 内容写入运行时环境。include 与快照的关系如果你依赖组件类名上的 CSS 属性例如用快照断言计算后的样式就必须通过include开启 CSS 处理因为默认情况下 Vitest 导出的只是 Proxy不会真正解析 CSS。这一点在文档的警告中也有强调后面「CSS Modules 的 Proxy 行为」一节会展开说明。css.exclude指定哪些 CSS 返回空内容类型RegExp | RegExp[]默认值[]exclude用于匹配「将返回空 CSS 文件」的路径。命中排除规则的文件会被替换为空字符串从而绕过 Vite 的后续处理减少测试开销。// vitest.config.ts export default defineConfig({ test: { css: { exclude: [/vendor\.css$/, /node_modules\//], }, }, })exclude的优先级高于include——同一文件若同时命中两者shouldProcessCSS会先命中exclude分支返回false。css.modulesCSS Modules 处理配置类型{ classNameStrategy? }默认值{}当你决定处理 CSS 文件后可以配置 CSS Modules 内部类名是否需要 scoped作用域化。css.modules.classNameStrategy类型stable | scoped | non-scoped默认值stable三者的差异直接对应 css-modules.ts 中generateScopedClassName的实现export function generateScopedClassName( strategy: CSSModuleScopeStrategy, name: string, filename: string, ): string | null { if (strategy scoped) { return null // 交给 Vite 默认的 generateScopedName 方法 } if (strategy non-scoped) { return name // 不哈希直接用原始类名 } const hash generateCssFilenameHash(filename) return _${name}_${hash} // stable_name_哈希 }stable默认类名生成规则为_${name}_${hashedFilename}。其中哈希仅基于文件路径计算——generateCssFilenameHash 使用hash(sha1, filepath, hex).slice(0, 6)取前 6 位十六进制。这意味着修改 CSS 内容不会改变类名但重命名文件或把文件移动到其他目录会导致类名变化。如果你在使用快照snapshot功能这个策略非常有用——类名不会因为样式内容的微调而破坏快照。scoped类名按常规方式生成遵循 Vite 的css.modules.generateScopedName方法前提是你配置了该方法且启用了 CSS 处理。默认情况下文件名会生成_${name}_${hash}形式的类名其中哈希包含文件名与文件内容。关键细节当策略为scoped时config.ts 中if (!browserEnabled classNameStrategy ! scoped)的条件为假Vitest不会覆盖Vite 的css.modules.generateScopedName从而完全交由 Vite 的默认机制处理。non-scoped类名不做哈希处理直接使用原始类名。这在你不关心类名唯一性、希望断言里出现直观的原始类名时很有用。CSS Modules 的 Proxy 行为默认导出文档特别警告默认情况下 Vitest 导出的是 Proxy绕过 CSS Modules 的真实处理。如果你依赖类上的 CSS 属性必须用include开启 CSS 处理。对应实现位于 cssEnabler.ts当文件是 CSS Module 且未命中处理规则时会生成如下代理模块export default new Proxy(Object.create(null), { get(_, style) { return _${style}_${hash} // stable/scoped 策略下 }, })对于non-scoped策略Proxy 返回原始style名见getCSSModuleProxyReturn的non-scoped分支对于其他策略Proxy 返回_${name}_${hashedFilename}且哈希基于相对测试 root 的文件路径计算relative(viteConfig.test.root, id)。这样做的意义即使 CSS 没有被真实处理import styles from ./x.module.css之后styles.foo依然返回一个可预期的字符串而不会得到undefined从而不影响组件运行时的行为。实际配置示例示例 1处理所有 CSS含 CSS Modules// vitest.config.ts export default defineConfig({ test: { css: true, }, })等价于include: [/./]所有 CSS 与 CSS Modules 都进入 Vite 管线。示例 2只处理 CSS Modules且类名不哈希// vitest.config.ts export default defineConfig({ test: { css: { include: [/\.module\.css$/], modules: { classNameStrategy: non-scoped, }, }, }, })适合在快照中直接断言原始类名如styles.button返回button。示例 3默认跳过 CSS仅排除个别文件// vitest.config.ts export default defineConfig({ test: { css: { exclude: [/global\.css$/], // include 为空 → 其余 CSS 一律不处理 }, }, })默认值与类型定义从 defaults.ts 可以看到默认配置为{ include: [] }类型定义位于 types/config.tscss?: | boolean | { include?: RegExp | RegExp[] exclude?: RegExp | RegExp[] modules?: { classNameStrategy?: CSSModuleScopeStrategy // stable | scoped | non-scoped } }配置解析时resolveConfig.ts 会对modules与classNameStrategy补默认值resolved.css.modules ?? {} resolved.css.modules.classNameStrategy ?? stable也就是说即使你只写了css: { include: [...] }classNameStrategy也会被规范为stable。小结与决策建议场景推荐配置测试需要真实样式与计算后的类名css: true或css: { include: [/./] }只处理少量样式文件其余跳过css: { include: [pattern] }使用快照且不希望类名因内容变化而变动css.modules.classNameStrategy: stable默认类名需随文件内容变化严格作用域css.modules.classNameStrategy: scoped快照中直接断言原始类名css.modules.classNameStrategy: non-scoped最后再提醒两点其一css配置对浏览器模式测试无效浏览器测试由真实浏览器渲染样式其二默认的 Proxy 导出虽然保证了 CSS Modules 导入不会报错但它不包含真实的 CSS 属性凡是依赖类上样式的断言都必须显式开启 CSS 处理。【免费下载链接】vitestNext generation testing framework powered by Vite.项目地址: https://gitcode.com/GitHub_Trending/vi/vitest创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考